/* 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 <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
*/
#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)) ;
//$B%5%$%:$O:GBg(B65535$B%P%$%H(B
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;i<l-1;i++)
fprintf(fp, " ");
}
xmlResult xml_save_file(gchar *filename, xmlDoc *doc)
{
FILE *fp;
fp = fopen(filename, "w");
if(fp == NULL){
perror("fopen");
return(XML_NG);
}
fprintf(fp, "<?xml");
if(doc->version)
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, "</%s>\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;i<l;i++)
printf("| ");
printf("|- ");
}
static void print_indent2(int l){
int i;
for(i=0;i<l;i++)
printf("| ");
printf("| ");
}
static void xml_print_tree_internal(GNode *node, gpointer data){
NODE_DATA *node_data;
node_data = (NODE_DATA *)(node->data);
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);
// <xxx/>$B$N>l9g$K$OBP1~$9$k%(%s%I%?%0$,$J$$(B
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;
}
syntax highlighted by Code2HTML, v. 0.9.1