/* Copyright (C) 2001-2002 Kenichi Suto * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* #include #include #include #include */ #include "defs.h" #include "xml.h" #include "xmlinternal.h" static void xml_save_file_internal(GNode *node, gpointer data); static void xml_print_tree_internal(GNode *node, gpointer data); static void xml_destroy_tree_internal(GNode *node, gpointer data); struct special_char { guchar special; gchar *encoded; }; static struct special_char special[] = {{'&', "&"}, {'\"', """}, {'<', "<"}, {'>', ">"}, {0, NULL}}; xmlDoc *xml_doc_new() { GNode *root; xmlDoc *doc; NODE_DATA *node_data; doc = (xmlDoc *)calloc(sizeof(xmlDoc), 1); doc->version = NULL; doc->encoding = NULL; node_data = (NODE_DATA *)calloc(sizeof(NODE_DATA), 1); node_data->name = NULL; node_data->content = NULL; node_data->attr = NULL; node_data->depth = 0; node_data->doc = doc; root = g_node_new((gpointer)node_data); doc->root = root; return(doc); } xmlDoc *xml_parse_file(gchar *filename) { unsigned int l; GNode *root; xmlDoc *doc; NODE_DATA *node_data; char buff[65535]; FILE *fp; fp = fopen(filename, "r"); if(fp == NULL){ perror("fopen"); return(NULL); } memset (buff, 0, sizeof(buff)) ; //サイズは最大65535バイト l = fread(buff, 1, sizeof(buff), fp); fclose(fp); if(l <= 0){ return(NULL); } doc = (xmlDoc *)calloc(sizeof(xmlDoc), 1); doc->version = NULL; doc->encoding = NULL; node_data = (NODE_DATA *)calloc(sizeof(NODE_DATA), 1); node_data->name = NULL; node_data->content = NULL; node_data->attr = NULL; node_data->depth = 0; node_data->doc = doc; root = g_node_new((gpointer)node_data); doc->root = root; parse_buffer(root, buff, l); return(doc); } void tag_indent(FILE *fp, int l){ int i; for(i=0;iversion) fprintf(fp, " version=\"%s\"", doc->version); if(doc->encoding) fprintf(fp, " encoding=\"%s\"", doc->encoding); fprintf(fp, "?>\n"); xml_save_file_internal(doc->root, fp); fclose(fp); return(XML_OK); } static void xml_save_file_internal(GNode *node, gpointer data){ FILE *fp; NODE_DATA *node_data; gchar *tmp_p; fp = (FILE *)data; node_data = (NODE_DATA *)(node->data); if(node_data->name){ tag_indent(fp, node_data->depth); fprintf(fp, "<%s",node_data->name); if(node_data->attr != NULL){ GList *list; NODE_ATTR *attr; list = g_list_first(node_data->attr); while(list){ attr = (NODE_ATTR *)(list->data); tmp_p = special_to_encoded(attr->value); fprintf(fp, " %s=\"%s\"", attr->name, tmp_p); free(tmp_p); list = g_list_next(list); } } fprintf(fp, ">"); if(G_NODE_IS_LEAF(node)){ if (node_data->content != NULL){ tmp_p = special_to_encoded(node_data->content); fprintf(fp, "%s", tmp_p); free(tmp_p); } } else { fprintf(fp, "\n"); g_node_children_foreach(node, G_TRAVERSE_ALL, (GNodeForeachFunc)xml_save_file_internal, (gpointer)fp); tag_indent(fp, node_data->depth); } if(node_data->name) fprintf(fp, "\n",node_data->name); } else { g_node_children_foreach(node, G_TRAVERSE_ALL, (GNodeForeachFunc)xml_save_file_internal, (gpointer)fp); } } xmlResult xml_print_tree(xmlDoc *doc){ xml_print_tree_internal((GNode *)doc->root, NULL); return(XML_OK); } static void print_indent(int l){ int i; for(i=0;idata); if(node_data->name){ print_indent(node_data->depth); printf("%s", node_data->name); if(node_data->attr != NULL){ GList *list; NODE_ATTR *attr; list = g_list_first(node_data->attr); while(list){ attr = (NODE_ATTR *)(list->data); g_print(" %s=%s", attr->name, attr->value); list = g_list_next(list); } } g_print("\n"); if(G_NODE_IS_LEAF(node)){ print_indent2(node_data->depth); if(node_data->content != NULL){ printf(">%s<\n", node_data->content); } else { printf("NULL\n"); } } else { g_node_children_foreach(node, G_TRAVERSE_ALL, (GNodeForeachFunc)xml_print_tree_internal, (gpointer)NULL); } } else { g_node_children_foreach(node, G_TRAVERSE_ALL, (GNodeForeachFunc)xml_print_tree_internal, (gpointer)NULL); } } xmlNode *xml_add_child(xmlNode *parent, gchar *name, gchar *content){ NODE_DATA *node_data; GNode *child; if(name == NULL) return(NULL); node_data = (NODE_DATA *)calloc(sizeof(NODE_DATA), 1); if(!node_data){ return(NULL); } node_data->name = strdup(name); node_data->attr = NULL; node_data->depth = ((NODE_DATA *)(parent->data))->depth + 1; node_data->doc = ((NODE_DATA *)(parent->data))->doc; if(content == NULL) node_data->content = NULL; else node_data->content = strdup(content); child = g_node_new((gpointer)node_data); g_node_append(parent, child); return(child); } xmlNode *xml_get_child(xmlNode *node){ return(node->children); } xmlNode *xml_get_next(xmlNode *node){ return(node->next); } gchar *xml_get_content(xmlNode *node){ if(((NODE_DATA *)(node->data))->content) return(((NODE_DATA *)(node->data))->content); else return(strdup("")); } gchar *xml_get_name(xmlNode *node){ return(((NODE_DATA *)(node->data))->name); } static void xml_destroy_tree_internal(GNode *node, gpointer data){ NODE_DATA *node_data; node_data = (NODE_DATA *)(node->data); if(G_NODE_IS_LEAF(node)){ if(node_data->name) free(node_data->name); if(node_data->content) free(node_data->content); if(node_data->attr != NULL){ GList *list; NODE_ATTR *attr; list = g_list_first(node_data->attr); while(list){ attr = (NODE_ATTR *)(list->data); if(attr->name) free(attr->name); if(attr->value) free(attr->value); free(attr); list = g_list_next(list); } } } else { g_node_children_foreach(node, G_TRAVERSE_ALL, (GNodeForeachFunc)xml_destroy_tree_internal, (gpointer)NULL); } } xmlResult xml_destroy_document(xmlDoc *doc){ xml_destroy_tree_internal(doc->root, NULL); g_node_destroy((GNode *)doc->root); free(doc->version); free(doc->encoding); free(doc); return(XML_OK); } gchar *special_to_encoded(gchar *text){ gchar buff[65536]; gchar *p; gint i; gint j; p = text; j = 0; while(*p){ for(i=0; ; i ++){ if(special[i].encoded == NULL) { buff[j] = *p; j++; break; } if(*p == special[i].special){ strcpy(&buff[j], special[i].encoded); j += strlen(special[i].encoded); break; } } p++; } buff[j] = '\0'; return(strdup(buff)); } gchar *encoded_to_special(gchar *text){ gchar buff[65536]; gchar *p; gint i; gint j; // g_print("encoded_to_special\n"); p = text; j = 0; while(*p){ if(*p == '&'){ // g_print("& found\n"); for(i=0; ; i ++){ if(special[i].encoded == NULL) { buff[j] = *p; j++; p++; break; } if(strstr(p, special[i].encoded) == p){ // g_print("encoded %s found\n", special[i].encoded); buff[j] = special[i].special; j ++; p += strlen(special[i].encoded); } } } else { buff[j] = *p; j++; p++; } } buff[j] = '\0'; return(strdup(buff)); } gchar *xml_get_attr(xmlNode *node, gchar *name){ GList *list; NODE_ATTR *attr; list = ((NODE_DATA *)(node->data))->attr; while(list){ attr = (NODE_ATTR *)(list->data); if(strcmp(attr->name, name) == 0){ return(attr->value); } list = g_list_next(list); } return(NULL); } xmlResult xml_set_attr(xmlNode *node, gchar *name, gchar *value){ NODE_ATTR *attr; attr = (NODE_ATTR *)calloc(sizeof(NODE_ATTR), 1); attr->name = strdup(name); attr->value = strdup(value); ((NODE_DATA *)(node->data))->attr = g_list_append(((NODE_DATA *)(node->data))->attr, attr); return(XML_OK); } xmlResult parse_attribute(GNode *node, gchar *tag){ gchar *p, *p2, *p3; NODE_ATTR *attr; gint end; gchar *tmp_val; // g_print("parse_attribute() start\n"); // g_print("tag = %s\n", tag); p = strchr(tag, ' '); if(p == NULL){ // g_print("parse_attribute() end1\n"); return(XML_OK); } p++; while(1){ // g_print("p = %s\n", p); p2 = strchr(p, '='); if(p2 == NULL){ // g_print("parse_attribute() end2\n"); return(XML_OK); } attr = (NODE_ATTR *)calloc(sizeof(NODE_ATTR), 1); attr->name = g_strndup(p, p2 - p); p2 ++; if(*p2 == '\"') p2++; p3 = p2; while(1){ if((*p3 == ' ') || (*p3 == '\"')) { end = 0; break; } if((*p3 == '\0') || (*p3 == ' ') || (*p3 == '>') || (*p3 == '\"')) { end = 1; break; } p3 ++; } tmp_val = g_strndup(p2, p3 - p2); attr->value = encoded_to_special(tmp_val); free(tmp_val); // g_print("attr : %s = %s\n", attr->name, attr->value); ((NODE_DATA *)node->data)->attr = g_list_append(((NODE_DATA *)node->data)->attr, attr); if(end) { // g_print("parse_attribute() end3\n"); return(XML_OK); } else { p3 ++; p = p3 + 1; } } // g_print("parse_attribute() end4\n"); } void parse_declaration(GNode *node, gchar *tag) { gchar attr[512]; xmlDoc *doc; g_assert(node != NULL); doc = ((NODE_DATA *)(node->data))->doc; g_assert(doc != NULL); get_attr(tag, "version", attr); doc->version = strdup(attr); get_attr(tag, "encoding", attr); doc->encoding = strdup(attr); } xmlResult parse_buffer(GNode *parent, gchar *text, guint length) { gchar *p; gchar start_tag[512]; gchar tag_name[512]; gchar body[65536]; gchar *content; gint content_length; gint body_length; GNode *node; gboolean no_end_tag; // g_print("parse_buffer() start\n"); /* { gchar *p; p = g_strndup(text, length); pppppppp g_print("text = %s\n", p); free(p); } */ g_assert(text != NULL); body_length = 0; p = text; while((p - text) < length){ if(*p == '<'){ if(body_length != 0){ // ((NODE_DATA *)(parent->data))->content = strdup(body); ((NODE_DATA *)(parent->data))->content = encoded_to_special(body); body[0] = '\0'; body_length = 0; } no_end_tag = FALSE; get_start_tag(p, start_tag); // の場合には対応するエンドタグがない if(start_tag[strlen(start_tag) - 1] == '/'){ start_tag[strlen(start_tag) - 1] = '\0'; no_end_tag = TRUE; } get_tag_name(start_tag, tag_name); if(start_tag[0] == '?'){ if(start_tag[strlen(start_tag) - 1] == '?'){ start_tag[strlen(start_tag) - 1] = '\0'; } parse_declaration(parent, &start_tag[1]); skip_start_tag(&p, tag_name); continue; } node = xml_add_child(parent, tag_name, NULL); parse_attribute(node, start_tag); if(no_end_tag == FALSE){ get_content(p, tag_name, &content, &content_length); parse_buffer(node, content, content_length); skip_end_tag(&p, tag_name); } else { skip_start_tag(&p, tag_name); } } else if (*p == '\n') { p++; } else { body[body_length] = *p; body_length ++; body[body_length] = '\0'; p++; } } if(body_length != 0){ // ((NODE_DATA *)(parent->data))->content = strdup(body); ((NODE_DATA *)(parent->data))->content = encoded_to_special(body); } // g_print("parse_buffer() end\n"); return XML_OK; }