📄 svg_parser.c
字号:
/* * GPAC Multimedia Framework * * Authors: Cyril Concolato - Jean le Feuvre - Jean-Claude Moissinac * Copyright (c) 2005-200X ENST * All rights reserved * * This file is part of GPAC / SVG Loader module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "svg_parser.h"#include <gpac/options.h>#include <gpac/internal/terminal_dev.h>#ifndef GPAC_DISABLE_SVGBool xmllib_is_init = 0;static void svg_init_root_element(SVGParser *parser, SVG_SA_svgElement *root_svg){ if (root_svg->width.type == SVG_NUMBER_VALUE) { parser->svg_w = FIX2INT(root_svg->width.value); parser->svg_h = FIX2INT(root_svg->height.value); } else { /* if unit for width & height is in percentage, then the only meaningful value for width and height is 100 %. In this case, we don't specify a value. It will be assigned by the renderer */ parser->svg_w = parser->svg_h = 0; } gf_sg_set_scene_size_info(parser->graph, parser->svg_w, parser->svg_h, 1); gf_sg_set_root_node(parser->graph, (GF_Node *)root_svg);}defered_element *list_dichotomic_search(GF_List *ptr, const char *search_id, s32 *index){ s32 tst_value; s32 first = 0; s32 last = gf_list_count(ptr)-1; s32 current = -1; defered_element *de = NULL; Bool found = 0; /* dichotomic search in the sorted list of defered elements */ while (first<=last) { current = (first+last)/2; de = (defered_element *)gf_list_get(ptr, current); tst_value = strcmp(search_id, &(de->target_id[1])); if (tst_value==0) { found = 1; break; } else if (tst_value>0) first = current +1; else last = current -1; } if (index) *index=current; /* index where the item could be inserted if necessary */ return (found?de:NULL);}void svg_entity_decl(void *user_data, const xmlChar *name, int type, const xmlChar *publicId, const xmlChar *systemId, xmlChar *content){ SVGParser *parser = (SVGParser *)user_data; xmlEntityPtr ent = (xmlEntityPtr)malloc(sizeof(xmlEntity)); if (ent) { ent->name = strdup(name); ent->type = type; ent->ExternalID = strdup(publicId); ent->SystemID = strdup(systemId); ent->content = strdup(content); gf_list_add(parser->entities, ent); }}void svg_cdata_block(void *user_data, const xmlChar * value, int len){ SVGParser *parser = (SVGParser *)user_data; parser->sax_state = STARTSVG;}void svg_start_document(void *user_data){ SVGParser *parser = (SVGParser *)user_data; parser->sax_state = STARTSVG; parser->unknown_depth = 0; parser->entities = gf_list_new(); if (!parser->entities) { parser->sax_state = ERROR; // TODO implement a safe cleaning if errorif (!elt) { return; }}void svg_end_document(void *user_data){ SVGParser *parser = (SVGParser *)user_data; parser->sax_state = FINISHSVG;}xmlEntityPtr svg_get_entity(void * user_data, const xmlChar *name){ SVGParser *parser = (SVGParser *)user_data; u32 i, count; count = gf_list_count(parser->entities); for (i=0; i<count; i++) { xmlEntityPtr ent = gf_list_get(parser->entities, i); if (!strcmp(ent->name, name)) { return ent;// and replace entity by ent->content } } return xmlGetPredefinedEntity(name);}Bool is_svg_script_element(SVG_SA_Element *elt){ u32 tag = elt->sgprivate->tag; return (tag==TAG_SVG_script);}Bool is_svg_text_element(SVG_SA_Element *elt){ u32 tag = elt->sgprivate->tag; return ((tag==TAG_SVG_text)||(tag==TAG_SVG_textArea)||(tag==TAG_SVG_tspan));}Bool is_svg_anchor_tag(u32 tag){ return (tag == TAG_SVG_a);}Bool is_svg_animation_tag(u32 tag){ return (tag == TAG_SVG_set || tag == TAG_SVG_animate || tag == TAG_SVG_animateColor || tag == TAG_SVG_animateTransform || tag == TAG_SVG_animateMotion || tag == TAG_SVG_discard)?1:0;}void svg_characters(void *user_data, const xmlChar *ch, s32 len){ SVGParser *parser = (SVGParser *)user_data; SVG_SA_Element *elt = (SVG_SA_Element *)gf_list_get(parser->svg_node_stack,gf_list_count(parser->svg_node_stack)-1); s32 baselen = 0; if (is_svg_text_element(elt)) { SVG_SA_textElement *text = (SVG_SA_textElement *)elt; char *tmp = (char *)ch; /* suppress begining spaces */ if ((!text->core->space)||(text->core->space != XML_SPACE_PRESERVE)) { while ((*tmp == ' ' || *tmp=='\n')&& (len>0)) { tmp++; len--; } } if (text->textContent) { baselen = strlen(text->textContent); text->textContent = (char *)realloc(text->textContent,baselen+len+1); } else text->textContent = (char *)malloc(len+1); strncpy(&text->textContent[baselen], tmp, len); // TODO verify how to manage text coding type text->textContent[baselen+len]=0; /* suppress ending spaces */ if ((!text->core->space)||(text->core->space != XML_SPACE_PRESERVE)) { tmp = &(text->textContent[baselen+len - 1]); while (*tmp == ' ' || *tmp=='\n') tmp--; tmp++; *tmp = 0; } gf_node_changed((GF_Node *)elt, NULL); }#if 0 if (is_svg_script_element(elt)) { SVG_SA_scriptElement *script = (SVG_SA_scriptElement *)elt; }#endif}// TODO verifiy good practices to replace entitiesxmlChar *svg_expand_entities(SVGParser *parser, xmlChar *originalStyle){ xmlChar *style = strdup(originalStyle); xmlChar *newStyle; u32 len = strlen(style); Bool expanded=0; xmlEntityPtr ent; u32 newlen; u32 i, j; do { char *str = style; len = strlen(style); expanded=0; for (i = 0; i < len+1; i++) { if (str[i] == '&') { for (j=0; j<len+1; j++) { if (str[j] == ';' || str[j] == 0) { char *value_string; u32 entity_len = 0; entity_len = j - i -1; if (entity_len) { value_string = (char *) malloc(sizeof(char) * (entity_len+1)); memcpy(value_string, str+i+1, entity_len); value_string[entity_len] = 0; ent = svg_get_entity(parser, value_string); if (ent) { newlen = strlen(ent->content); newStyle = (char *) malloc(sizeof(char) * (len+newlen-entity_len)); memcpy(newStyle, style, i); memcpy(newStyle+i, ent->content, newlen); memcpy(newStyle+i+newlen, style+i+entity_len+1, len-i-entity_len-1); newStyle[len+newlen-entity_len-2] = 0; free(style); style = newStyle; expanded = 1; } } } } } } } while (expanded==1); return style;}void svg_start_element(void *user_data, const xmlChar *name, const xmlChar **attrs){ SVGParser *parser = (SVGParser *)user_data; SVG_SA_Element *elt; switch(parser->sax_state) { case STARTSVG: if (!stricmp((char *)name, "svg")) { elt = svg_parse_sax_element(parser, name, attrs, NULL); if (!elt) { parser->last_error = GF_SG_UNKNOWN_NODE; parser->sax_state = ERROR; return; } else { svg_init_root_element(parser, (SVG_SA_svgElement *)elt); } parser->svg_node_stack = gf_list_new(); if (!parser->svg_node_stack) { parser->sax_state = ERROR; return; } gf_list_add(parser->svg_node_stack, elt); parser->sax_state = SVGCONTENT; parser->loader_status = 2; } else { parser->prev_sax_state = STARTSVG; parser->unknown_depth++; parser->sax_state = UNKNOWN; } break; case SVGCONTENT: elt = svg_parse_sax_element(parser, name, attrs, (SVG_SA_Element *)gf_list_get(parser->svg_node_stack,gf_list_count(parser->svg_node_stack)-1)); if (elt) gf_list_add(parser->svg_node_stack, elt); else { parser->prev_sax_state = SVGCONTENT; parser->unknown_depth++; parser->sax_state = UNKNOWN; } break; case UNKNOWN: parser->unknown_depth++; break; }}void svg_end_element(void *user_data, const xmlChar *name){ SVGParser *parser = (SVGParser *)user_data; switch(parser->sax_state) { case STARTSVG: break; case SVGCONTENT: gf_list_rem_last(parser->svg_node_stack); break; case UNKNOWN: parser->unknown_depth--; if (parser->unknown_depth==0) parser->sax_state = parser->prev_sax_state; break; } /*JLF: there's a pb with endDocument, I force it here*/ if (!stricmp(name, "svg")) parser->sax_state = FINISHSVG;}/* end of SAX related functions *//* Generic Scene Graph handling functions for ID */void svg_parse_element_id(SVGParser *parser, SVG_SA_Element *elt, char *nodename){ u32 id = 0; SVG_SA_Element *unided_elt; unided_elt = (SVG_SA_Element *)gf_sg_find_node_by_name(parser->graph, nodename); if (unided_elt) { id = gf_node_get_id((GF_Node *)unided_elt); if (svg_has_been_IDed(parser, nodename)) unided_elt = NULL; } else { id = svg_get_node_id(parser, nodename); } gf_node_set_id((GF_Node *)elt, id, nodename); if (unided_elt) gf_node_replace((GF_Node *)unided_elt, (GF_Node *)elt, 0); gf_list_add(parser->ided_nodes, elt);} Bool svg_has_been_IDed(SVGParser *parser, xmlChar *node_name){ u32 i, count; count = gf_list_count(parser->ided_nodes); for (i=0; i<count; i++) { GF_Node *n = gf_list_get(parser->ided_nodes, i); const char *nname = gf_node_get_name(n); if (!strcmp(nname, node_name)) return 1; } return 0;}u32 svg_get_next_node_id(SVGParser *parser){ u32 ID; ID = gf_sg_get_next_available_node_id(parser->graph); if (ID>parser->max_node_id) parser->max_node_id = ID; return ID;}u32 svg_get_node_id(SVGParser *parser, xmlChar *nodename){ GF_Node *n; u32 ID; if (sscanf(nodename, "N%d", &ID) == 1) { ID ++; n = gf_sg_find_node(parser->graph, ID); if (n && 0) { u32 nID = svg_get_next_node_id(parser); const char *nname = gf_node_get_name(n); gf_node_set_id(n, nID, nname); } if (parser->max_node_id<ID) parser->max_node_id=ID; } else { ID = svg_get_next_node_id(parser); } return ID;}/* end of Generic Scene Graph handling functions for ID *//* DOM Related functions *//* Parses all the attributes of an element except id */ void svg_parse_dom_attributes(SVGParser *parser, xmlNodePtr node, SVG_SA_Element *elt, u8 anim_value_type, u8 anim_transform_type){ xmlAttrPtr attributes; char *style; u32 tag; tag = gf_node_get_tag((GF_Node*)elt); /* Parsing the style attribute */ if ((style = xmlGetProp(node, "style"))) gf_svg_parse_style((GF_Node *)elt, style); /* Parsing all the other attributes, with a special case for the id attribute */ attributes = node->properties; while (attributes) { if (attributes->type == XML_ATTRIBUTE_NODE) { if (!stricmp(attributes->name, "id")) { /* should have been done in svg_parse_element_id */ } else if (!stricmp(attributes->name, "attributeName")) { /* we don't parse the animation element attributes here */ } else if (!stricmp(attributes->name, "type")) { if (tag == TAG_SVG_animateTransform) { /* we don't parse the animation element attributes here */ } else { GF_FieldInfo info; if (!gf_node_get_field_by_name((GF_Node *)elt, "type", &info)) { gf_svg_parse_attribute((GF_Node *)elt, &info, attributes->children->content, 0, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -