Compare commits

..

No commits in common. "master" and "mxml-2019-03-a" have entirely different histories.

5 changed files with 309 additions and 272 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
*~

View File

@ -33,7 +33,7 @@
mxml_find_nodes(tree, xml_path, &nodelist); mxml_find_nodes(tree, xml_path, &nodelist);
which support a subset of the XPath specification. Another set of which support a subset of the XPath specification. Another set of
functions is available to retrieve attributes and values from nodes functions is availabe to retrieve attributes and values from nodes
in the tree and for manipulating nodes, like replacing, adding and in the tree and for manipulating nodes, like replacing, adding and
deleting nodes. deleting nodes.
@ -60,8 +60,6 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <string>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <windows.h> #include <windows.h>
@ -93,6 +91,9 @@
#endif #endif
#include "mxml.h" #include "mxml.h"
#ifndef HAVE_STRLCPY
#include "strlcpy.h"
#endif
#define XML_INDENT " " #define XML_INDENT " "
@ -124,54 +125,6 @@ static void *mxml_malloc(size_t size);
static void *mxml_realloc(void *p, size_t size); static void *mxml_realloc(void *p, size_t size);
static void mxml_free(void *p); static void mxml_free(void *p);
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless size == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
static size_t mxml_strlcpy(char *dst, const char *src, size_t size)
{
char *d = dst;
const char *s = src;
size_t n = size;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (size != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++);
}
return (s - src - 1); /* count does not include NUL */
}
/*------------------------------------------------------------------*/
static std::string toString(int i)
{
char buf[100];
snprintf(buf, sizeof(buf), "%d", i);
return buf;
}
/*------------------------------------------------------------------*/
static std::string toStrerror(int err)
{
char buf[256];
snprintf(buf, sizeof(buf), "errno %d (%s)", err, strerror(err));
return buf;
}
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
void *mxml_malloc(size_t size) void *mxml_malloc(size_t size)
@ -197,7 +150,9 @@ void mxml_free(void *p)
int mxml_write_line(MXML_WRITER *writer, const char *line) int mxml_write_line(MXML_WRITER *writer, const char *line)
{ {
int len = strlen(line); unsigned len;
len = strlen(line);
if (writer->buffer) { if (writer->buffer) {
if (writer->buffer_len + len >= writer->buffer_size) { if (writer->buffer_len + len >= writer->buffer_size) {
@ -205,7 +160,7 @@ int mxml_write_line(MXML_WRITER *writer, const char *line)
writer->buffer = (char *)mxml_realloc(writer->buffer, writer->buffer_size); writer->buffer = (char *)mxml_realloc(writer->buffer, writer->buffer_size);
assert(writer->buffer); assert(writer->buffer);
} }
memcpy(writer->buffer + writer->buffer_len, line, len+1); strcpy(writer->buffer + writer->buffer_len, line);
writer->buffer_len += len; writer->buffer_len += len;
return len; return len;
} else { } else {
@ -222,29 +177,28 @@ int mxml_write_line(MXML_WRITER *writer, const char *line)
*/ */
MXML_WRITER *mxml_open_buffer(void) MXML_WRITER *mxml_open_buffer(void)
{ {
MXML_WRITER *writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER)); char str[256], line[1000];
time_t now;
MXML_WRITER *writer;
writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
memset(writer, 0, sizeof(MXML_WRITER)); memset(writer, 0, sizeof(MXML_WRITER));
writer->translate = 1; writer->translate = 1;
writer->buffer_size = 10000; writer->buffer_size = 10000;
writer->buffer = (char *)mxml_malloc(writer->buffer_size); writer->buffer = (char *)mxml_malloc(10000);
assert(writer->buffer != NULL);
writer->buffer[0] = 0; writer->buffer[0] = 0;
writer->buffer_len = 0; writer->buffer_len = 0;
/* write XML header */ /* write XML header */
mxml_write_line(writer, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"); strcpy(line, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
mxml_write_line(writer, line);
if (mxml_suppress_date_flag == 0) { time(&now);
time_t now = time(NULL); strcpy(str, ctime(&now));
std::string str = ctime(&now); str[24] = 0;
str.resize(24); sprintf(line, "<!-- created by MXML on %s -->\n", str);
std::string line = ""; if (mxml_suppress_date_flag == 0)
line += "<!-- created by MXML on "; mxml_write_line(writer, line);
line += str;
line += " -->\n";
mxml_write_line(writer, line.c_str());
}
/* initialize stack */ /* initialize stack */
writer->level = 0; writer->level = 0;
@ -270,35 +224,32 @@ void mxml_suppress_date(int suppress)
*/ */
MXML_WRITER *mxml_open_file(const char *file_name) MXML_WRITER *mxml_open_file(const char *file_name)
{ {
MXML_WRITER* writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER)); char str[256], line[1000];
time_t now;
MXML_WRITER *writer;
writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
memset(writer, 0, sizeof(MXML_WRITER)); memset(writer, 0, sizeof(MXML_WRITER));
writer->translate = 1; writer->translate = 1;
writer->fh = open(file_name, O_RDWR | O_CREAT | O_TRUNC | O_TEXT, 0644); writer->fh = open(file_name, O_RDWR | O_CREAT | O_TRUNC | O_TEXT, 0644);
if (writer->fh == -1) { if (writer->fh == -1) {
std::string line = ""; sprintf(line, "Unable to open file \"%s\": ", file_name);
line += "Unable to open file \""; perror(line);
line += file_name;
line += "\": ";
line += toStrerror(errno);
fprintf(stderr, "%s\n", line.c_str());
mxml_free(writer); mxml_free(writer);
return NULL; return NULL;
} }
/* write XML header */ /* write XML header */
mxml_write_line(writer, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"); strcpy(line, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
if (mxml_suppress_date_flag == 0) { mxml_write_line(writer, line);
time_t now = time(NULL); time(&now);
std::string str = ctime(&now); strcpy(str, ctime(&now));
str.resize(24); str[24] = 0;
std::string line = ""; sprintf(line, "<!-- created by MXML on %s -->\n", str);
line += "<!-- created by MXML on "; if (mxml_suppress_date_flag == 0)
line += str; mxml_write_line(writer, line);
line += " -->\n";
mxml_write_line(writer, line.c_str());
}
/* initialize stack */ /* initialize stack */
writer->level = 0; writer->level = 0;
@ -314,10 +265,7 @@ MXML_WRITER *mxml_open_file(const char *file_name)
*/ */
void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate) void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate)
{ {
if (buf_size <= 6*src_len) { assert(buf_size > 6*src_len); // each input byte is expanded into 6 bytes at most
printf("mxml_encode: buffer size too small\n");
exit(0);
}
char *pd = buf; char *pd = buf;
const char* ps; const char* ps;
for (ps = src ; *ps ; ps++) { for (ps = src ; *ps ; ps++) {
@ -429,23 +377,24 @@ int mxml_set_translate(MXML_WRITER *writer, int flag)
int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent) int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent)
{ {
int i; int i;
char line[1000];
if (writer->element_is_open) { if (writer->element_is_open) {
mxml_write_line(writer, ">\n"); mxml_write_line(writer, ">\n");
writer->element_is_open = FALSE; writer->element_is_open = FALSE;
} }
std::string line = ""; line[0] = 0;
if (indent) if (indent)
for (i=0 ; i<writer->level ; i++) for (i=0 ; i<writer->level ; i++)
line += XML_INDENT; strlcat(line, XML_INDENT, sizeof(line)); // FIXME: truncated
line += "<"; strlcat(line, "<", sizeof(line));
unsigned len = strlen(name); unsigned len = strlen(name);
unsigned name_enc_size = len*6+10; unsigned name_enc_size = len*6+10;
char* name_enc = (char*)mxml_malloc(name_enc_size); char* name_enc = (char*)mxml_malloc(name_enc_size);
mxml_encode(name_enc, name_enc_size, name, strlen(name), writer->translate); mxml_encode(name_enc, name_enc_size, name, strlen(name), writer->translate);
line += name_enc; strlcat(line, name_enc, sizeof(line)); // FIXME: data will be truncated
/* put element on stack */ /* put element on stack */
if (writer->level == 0) if (writer->level == 0)
@ -458,7 +407,7 @@ int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent)
writer->element_is_open = TRUE; writer->element_is_open = TRUE;
writer->data_was_written = FALSE; writer->data_was_written = FALSE;
return mxml_write_line(writer, line.c_str()) == (int)line.length(); return mxml_write_line(writer, line) == (int)strlen(line);
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
@ -494,25 +443,27 @@ int mxml_end_element(MXML_WRITER *writer)
mxml_free(writer->stack[writer->level]); mxml_free(writer->stack[writer->level]);
if (writer->level == 0) if (writer->level == 0)
mxml_free(writer->stack); mxml_free(writer->stack);
const char* line = "/>\n"; char line[10];
strcpy(line, "/>\n");
return mxml_write_line(writer, line) == (int)strlen(line); return mxml_write_line(writer, line) == (int)strlen(line);
} }
std::string line = ""; char line[1000];
line[0] = 0;
if (!writer->data_was_written) { if (!writer->data_was_written) {
for (i=0 ; i<writer->level ; i++) for (i=0 ; i<writer->level ; i++)
line += XML_INDENT; strlcat(line, XML_INDENT, sizeof(line)); // FIXME: truncated
} }
line += "</"; strlcat(line, "</", sizeof(line));
line += writer->stack[writer->level]; strlcat(line, writer->stack[writer->level], sizeof(line)); // FIXME: truncated
mxml_free(writer->stack[writer->level]); mxml_free(writer->stack[writer->level]);
if (writer->level == 0) if (writer->level == 0)
mxml_free(writer->stack); mxml_free(writer->stack);
line += ">\n"; strlcat(line, ">\n", sizeof(line));
writer->data_was_written = FALSE; writer->data_was_written = FALSE;
return mxml_write_line(writer, line.c_str()) == (int)line.length(); return mxml_write_line(writer, line) == (int)strlen(line);
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
@ -522,21 +473,22 @@ int mxml_end_element(MXML_WRITER *writer)
*/ */
int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value) int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value)
{ {
char line[8192];
char buf[6*4096+10]; char buf[6*4096+10];
if (!writer->element_is_open) if (!writer->element_is_open)
return FALSE; return FALSE;
std::string line = ""; line[0] = 0;
line += " "; strlcat(line, " ", sizeof(line));
mxml_encode(buf, sizeof(buf), name, strlen(name), writer->translate); mxml_encode(buf, sizeof(buf), name, strlen(name), writer->translate);
line += buf; strlcat(line, buf, sizeof(line)); // FIXME: truncated
line += "=\""; strlcat(line, "=\"", sizeof(line));
mxml_encode(buf, sizeof(buf), value, strlen(value), writer->translate); mxml_encode(buf, sizeof(buf), value, strlen(value), writer->translate);
line += buf; strlcat(line, buf, sizeof(line)); // FIXME: truncated
line += "\""; strlcat(line, "\"", sizeof(line));
return mxml_write_line(writer, line.c_str()) == (int)line.length(); return mxml_write_line(writer, line) == (int)strlen(line);
} }
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
@ -557,7 +509,7 @@ int mxml_write_value(MXML_WRITER *writer, const char *data)
unsigned len = strlen(data); unsigned len = strlen(data);
unsigned size = 6*len + 1000; unsigned size = 6*len + 1000;
char* buf = (char*)mxml_malloc(size); char* buf = (char*)mxml_malloc(size);
memcpy(buf, data, len+1); strcpy(buf, data);
mxml_encode(buf, size, data, len, writer->translate); mxml_encode(buf, size, data, len, writer->translate);
int v = mxml_write_line(writer, buf) == (int)strlen(buf); int v = mxml_write_line(writer, buf) == (int)strlen(buf);
mxml_free(buf); mxml_free(buf);
@ -596,14 +548,15 @@ int mxml_write_comment(MXML_WRITER *writer, const char *string)
writer->element_is_open = FALSE; writer->element_is_open = FALSE;
} }
std::string line = ""; char line[1000];
line[0] = 0;
for (i=0 ; i<writer->level ; i++) for (i=0 ; i<writer->level ; i++)
line += XML_INDENT; strlcat(line, XML_INDENT, sizeof(line)); // FIXME: truncated
line += "<!-- "; strlcat(line, "<!-- ", sizeof(line));
line += string; strlcat(line, string, sizeof(line)); // FIXME: truncated
line += " -->\n"; strlcat(line, " -->\n", sizeof(line));
if (mxml_write_line(writer, line.c_str()) != (int)line.length()) if (mxml_write_line(writer, line) != (int)strlen(line))
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -682,8 +635,8 @@ PMXML_NODE mxml_create_root_node(void)
{ {
PMXML_NODE root; PMXML_NODE root;
root = (PMXML_NODE)calloc(1, sizeof(MXML_NODE)); root = (PMXML_NODE)calloc(sizeof(MXML_NODE), 1);
strcpy(root->name, "root"); // SAFE strcpy(root->name, "root");
root->node_type = DOCUMENT_NODE; root->node_type = DOCUMENT_NODE;
return root; return root;
@ -721,17 +674,16 @@ PMXML_NODE mxml_add_special_node_at(PMXML_NODE parent, int node_type, const char
/* initialize new node */ /* initialize new node */
pnode = &parent->child[idx]; pnode = &parent->child[idx];
memset(pnode, 0, sizeof(MXML_NODE)); memset(pnode, 0, sizeof(MXML_NODE));
mxml_strlcpy(pnode->name, node_name, sizeof(pnode->name)); strlcpy(pnode->name, node_name, sizeof(pnode->name));
pnode->node_type = node_type; pnode->node_type = node_type;
pnode->parent = parent; pnode->parent = parent;
parent->n_children++; parent->n_children++;
if (value && *value) { if (value && *value) {
int len = strlen(value); pnode->value = (char *)mxml_malloc(strlen(value)+1);
pnode->value = (char *)mxml_malloc(len+1);
assert(pnode->value); assert(pnode->value);
memcpy(pnode->value, value, len+1); strcpy(pnode->value, value);
} }
return pnode; return pnode;
@ -849,11 +801,9 @@ int mxml_add_attribute(PMXML_NODE pnode, const char *attrib_name, const char *at
pnode->attribute_value = (char**)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes+1)); pnode->attribute_value = (char**)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes+1));
} }
mxml_strlcpy(pnode->attribute_name+pnode->n_attributes*MXML_NAME_LENGTH, attrib_name, MXML_NAME_LENGTH); strlcpy(pnode->attribute_name+pnode->n_attributes*MXML_NAME_LENGTH, attrib_name, MXML_NAME_LENGTH);
int len = strlen(attrib_value); pnode->attribute_value[pnode->n_attributes] = (char *)mxml_malloc(strlen(attrib_value)+1);
pnode->attribute_value[pnode->n_attributes] = (char *)mxml_malloc(len+1); strcpy(pnode->attribute_value[pnode->n_attributes], attrib_value);
assert(pnode->attribute_value[pnode->n_attributes] != NULL);
memcpy(pnode->attribute_value[pnode->n_attributes], attrib_value, len+1);
pnode->n_attributes++; pnode->n_attributes++;
return TRUE; return TRUE;
@ -964,7 +914,7 @@ int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelis
/* evaluate [<@attrib>/<subnode>=<value>] */ /* evaluate [<@attrib>/<subnode>=<value>] */
while (*p2 && isspace((unsigned char)*p2)) while (*p2 && isspace((unsigned char)*p2))
p2++; p2++;
mxml_strlcpy(condition, p2, sizeof(condition)); strlcpy(condition, p2, sizeof(condition));
if (strchr(condition, ']')) if (strchr(condition, ']'))
*strchr(condition, ']') = 0; *strchr(condition, ']') = 0;
else else
@ -973,9 +923,9 @@ int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelis
if ((p3 = strchr(condition, '=')) != NULL) { if ((p3 = strchr(condition, '=')) != NULL) {
if (condition[0] == '@') { if (condition[0] == '@') {
cond_type[num_cond] = 1; cond_type[num_cond] = 1;
mxml_strlcpy(cond_name[num_cond], &condition[1], sizeof(cond_name[num_cond])); strlcpy(cond_name[num_cond], &condition[1], sizeof(cond_name[num_cond]));
} else { } else {
mxml_strlcpy(cond_name[num_cond], condition, sizeof(cond_name[num_cond])); strlcpy(cond_name[num_cond], condition, sizeof(cond_name[num_cond]));
} }
*strchr(cond_name[num_cond], '=') = 0; *strchr(cond_name[num_cond], '=') = 0;
@ -986,19 +936,19 @@ int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelis
while (*p3 && isspace(*p3)) while (*p3 && isspace(*p3))
p3++; p3++;
if (*p3 == '\"') { if (*p3 == '\"') {
mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond])); strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1])) while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\"') if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\"')
cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
} else if (*p3 == '\'') { } else if (*p3 == '\'') {
mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond])); strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1])) while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\'') if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\'')
cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
} else { } else {
mxml_strlcpy(cond_value[num_cond], p3, sizeof(cond_value[num_cond])); strlcpy(cond_value[num_cond], p3, sizeof(cond_value[num_cond]));
while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1])) while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0; cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
} }
@ -1148,7 +1098,7 @@ char *mxml_get_attribute(PMXML_NODE pnode, const char *name)
int mxml_replace_node_name(PMXML_NODE pnode, const char *name) int mxml_replace_node_name(PMXML_NODE pnode, const char *name)
{ {
mxml_strlcpy(pnode->name, name, sizeof(pnode->name)); strlcpy(pnode->name, name, sizeof(pnode->name));
return TRUE; return TRUE;
} }
@ -1156,16 +1106,15 @@ int mxml_replace_node_name(PMXML_NODE pnode, const char *name)
int mxml_replace_node_value(PMXML_NODE pnode, const char *value) int mxml_replace_node_value(PMXML_NODE pnode, const char *value)
{ {
int len = strlen(value);
if (pnode->value) if (pnode->value)
pnode->value = (char *)mxml_realloc(pnode->value, len+1); pnode->value = (char *)mxml_realloc(pnode->value, strlen(value)+1);
else if (value) else if (value)
pnode->value = (char *)mxml_malloc(len+1); pnode->value = (char *)mxml_malloc(strlen(value)+1);
else else
pnode->value = NULL; pnode->value = NULL;
if (value) if (value)
memcpy(pnode->value, value, len+1); strcpy(pnode->value, value);
return TRUE; return TRUE;
} }
@ -1211,7 +1160,7 @@ int mxml_replace_attribute_name(PMXML_NODE pnode, const char *old_name, const ch
if (i == pnode->n_attributes) if (i == pnode->n_attributes)
return FALSE; return FALSE;
mxml_strlcpy(pnode->attribute_name+i*MXML_NAME_LENGTH, new_name, MXML_NAME_LENGTH); strlcpy(pnode->attribute_name+i*MXML_NAME_LENGTH, new_name, MXML_NAME_LENGTH);
return TRUE; return TRUE;
} }
@ -1231,9 +1180,8 @@ int mxml_replace_attribute_value(PMXML_NODE pnode, const char *attrib_name, cons
if (i == pnode->n_attributes) if (i == pnode->n_attributes)
return FALSE; return FALSE;
int len = strlen(attrib_value); pnode->attribute_value[i] = (char *)mxml_realloc(pnode->attribute_value[i], strlen(attrib_value)+1);
pnode->attribute_value[i] = (char *)mxml_realloc(pnode->attribute_value[i], len+1); strcpy(pnode->attribute_value[i], attrib_value);
memcpy(pnode->attribute_value[i], attrib_value, len+1);
return TRUE; return TRUE;
} }
@ -1288,7 +1236,7 @@ int mxml_delete_attribute(PMXML_NODE pnode, const char *attrib_name)
mxml_free(pnode->attribute_value[i]); mxml_free(pnode->attribute_value[i]);
for (j=i ; j<pnode->n_attributes-1 ; j++) { for (j=i ; j<pnode->n_attributes-1 ; j++) {
mxml_strlcpy(pnode->attribute_name+j*MXML_NAME_LENGTH, pnode->attribute_name+(j+1)*MXML_NAME_LENGTH, MXML_NAME_LENGTH); strcpy(pnode->attribute_name+j*MXML_NAME_LENGTH, pnode->attribute_name+(j+1)*MXML_NAME_LENGTH);
pnode->attribute_value[j] = pnode->attribute_value[j+1]; pnode->attribute_value[j] = pnode->attribute_value[j+1];
} }
@ -1312,34 +1260,27 @@ int mxml_delete_attribute(PMXML_NODE pnode, const char *attrib_name)
*/ */
PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...) PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...)
{ {
std::string msg; char *msg, str[1000];
if (file_name && file_name[0]) {
msg += "XML read error in file \"";
msg += file_name;
msg += "\", line ";
msg += toString(line_number);
msg += ": ";
} else {
msg += "XML read error, line ";
msg += toString(line_number);
msg += ": ";
}
char str[1000];
va_list argptr; va_list argptr;
if (file_name && file_name[0])
sprintf(str, "XML read error in file \"%s\", line %d: ", file_name, line_number);
else
sprintf(str, "XML read error, line %d: ", line_number);
msg = (char *)mxml_malloc(error_size);
if (error)
strlcpy(error, str, error_size);
va_start(argptr, format); va_start(argptr, format);
vsnprintf(str, sizeof(str), (char *) format, argptr); vsprintf(str, (char *) format, argptr);
va_end(argptr); va_end(argptr);
msg += str; if (error)
strlcat(error, str, error_size);
if (error) { if (error_line)
mxml_strlcpy(error, msg.c_str(), error_size);
}
if (error_line) {
*error_line = line_number; *error_line = line_number;
}
mxml_free(msg);
mxml_free_tree(root); mxml_free_tree(root);
return NULL; return NULL;
@ -1683,13 +1624,17 @@ int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_
int entity_type[MXML_MAX_ENTITY]; /* internal or external */ int entity_type[MXML_MAX_ENTITY]; /* internal or external */
int entity_line_number[MXML_MAX_ENTITY]; int entity_line_number[MXML_MAX_ENTITY];
int nentity; int nentity;
int fh, length; int fh, length, len;
char *buffer;
int ip; /* counter for entity value */
char directoryname[FILENAME_MAX];
char filename[FILENAME_MAX];
int entity_value_length[MXML_MAX_ENTITY]; int entity_value_length[MXML_MAX_ENTITY];
int entity_name_length[MXML_MAX_ENTITY]; int entity_name_length[MXML_MAX_ENTITY];
PMXML_NODE root = mxml_create_root_node(); /* dummy for 'HERE' */ PMXML_NODE root = mxml_create_root_node(); /* dummy for 'HERE' */
for (int ip = 0; ip < MXML_MAX_ENTITY; ip++) for (ip = 0; ip < MXML_MAX_ENTITY; ip++)
entity_value[ip] = NULL; entity_value[ip] = NULL;
line_number = 1; line_number = 1;
@ -1699,19 +1644,17 @@ int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_
if (!buf || !(*buf) || !strlen(*buf)) if (!buf || !(*buf) || !strlen(*buf))
return 0; return 0;
char directoryname[FILENAME_MAX]; strcpy(directoryname, file_name);
mxml_strlcpy(directoryname, file_name, FILENAME_MAX);
mxml_dirname(directoryname); mxml_dirname(directoryname);
/* copy string to temporary space */ /* copy string to temporary space */
int len = strlen(*buf); buffer = (char *) mxml_malloc(strlen(*buf) + 1);
char* buffer = (char *) mxml_malloc(len+1);
if (buffer == NULL) { if (buffer == NULL) {
read_error(HERE, "Cannot allocate memory."); read_error(HERE, "Cannot allocate memory.");
status = 1; status = 1;
goto error; goto error;
} }
memcpy(buffer, *buf, len+1); strcpy(buffer, *buf);
p = strstr(buffer, "!DOCTYPE"); p = strstr(buffer, "!DOCTYPE");
if (p == NULL) { /* no entities */ if (p == NULL) { /* no entities */
@ -1914,16 +1857,15 @@ int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_
mxml_decode(replacement); mxml_decode(replacement);
if (entity_type[nentity] == EXTERNAL_ENTITY) { if (entity_type[nentity] == EXTERNAL_ENTITY) {
mxml_strlcpy(entity_reference_name[nentity], replacement, sizeof(entity_reference_name[nentity])); strcpy(entity_reference_name[nentity], replacement);
} else { } else {
int rlen = strlen(replacement); entity_value[nentity] = (char *) mxml_malloc(strlen(replacement));
entity_value[nentity] = (char *) mxml_malloc(rlen+1);
if (entity_value[nentity] == NULL) { if (entity_value[nentity] == NULL) {
read_error(HERE, "Cannot allocate memory."); read_error(HERE, "Cannot allocate memory.");
status = 1; status = 1;
goto error; goto error;
} }
memcpy(entity_value[nentity], replacement, rlen+1); strcpy(entity_value[nentity], replacement);
} }
mxml_free(replacement); mxml_free(replacement);
@ -1953,15 +1895,11 @@ int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_
/* read external file */ /* read external file */
for (i = 0; i < nentity; i++) { for (i = 0; i < nentity; i++) {
if (entity_type[i] == EXTERNAL_ENTITY) { if (entity_type[i] == EXTERNAL_ENTITY) {
std::string filename; if ( entity_reference_name[i][0] == DIR_SEPARATOR ) /* absolute path */
if ( entity_reference_name[i][0] == DIR_SEPARATOR ) { /* absolute path */ strcpy(filename, entity_reference_name[i]);
filename = entity_reference_name[i]; else /* relative path */
} else { /* relative path */ sprintf(filename, "%s%c%s", directoryname, DIR_SEPARATOR, entity_reference_name[i]);
filename += directoryname; fh = open(filename, O_RDONLY | O_TEXT, 0644);
filename += DIR_SEPARATOR;
filename += entity_reference_name[i];
}
fh = open(filename.c_str(), O_RDONLY | O_TEXT, 0644);
if (fh == -1) { if (fh == -1) {
line_number = entity_line_number[i]; line_number = entity_line_number[i];
@ -1995,7 +1933,7 @@ int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_
close(fh); close(fh);
/* recursive parse */ /* recursive parse */
if (mxml_parse_entity(&entity_value[i], filename.c_str(), error, error_size, error_line) != 0) { if (mxml_parse_entity(&entity_value[i], filename, error, error_size, error_line) != 0) {
status = 1; status = 1;
goto error; goto error;
} }
@ -2048,13 +1986,11 @@ int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_
} while (*p); } while (*p);
*pv = 0; *pv = 0;
mxml_free_tree(root);
error: error:
if (buffer != NULL) if (buffer != NULL)
mxml_free(buffer); mxml_free(buffer);
for (int ip = 0; ip < MXML_MAX_ENTITY; ip++) for (ip = 0; ip < MXML_MAX_ENTITY; ip++)
if (entity_value[ip] != NULL) if (entity_value[ip] != NULL)
mxml_free(entity_value[ip]); mxml_free(entity_value[ip]);
@ -2069,55 +2005,35 @@ error:
*/ */
PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line) PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line)
{ {
char *buf, line[1000];
int fh, length;
PMXML_NODE root;
if (error) if (error)
error[0] = 0; error[0] = 0;
int fh = open(file_name, O_RDONLY | O_TEXT, 0644); fh = open(file_name, O_RDONLY | O_TEXT, 0644);
if (fh == -1) { if (fh == -1) {
std::string msg = ""; sprintf(line, "Unable to open file \"%s\": ", file_name);
msg += "Cannot open file \""; strlcat(line, strerror(errno), sizeof(line));
msg += file_name; strlcpy(error, line, error_size);
msg += "\": ";
msg += toStrerror(errno);
mxml_strlcpy(error, msg.c_str(), error_size);
return NULL; return NULL;
} }
off_t length = lseek(fh, 0, SEEK_END); length = (int)lseek(fh, 0, SEEK_END);
lseek(fh, 0, SEEK_SET); lseek(fh, 0, SEEK_SET);
buf = (char *)mxml_malloc(length+1);
char* buf = (char *)mxml_malloc(length+1);
if (buf == NULL) { if (buf == NULL) {
close(fh); close(fh);
std::string msg = ""; sprintf(line, "Cannot allocate buffer: ");
msg += "Cannot allocate buffer size "; strlcat(line, strerror(errno), sizeof(line));
msg += toString(length); strlcpy(error, line, error_size);
msg += " for file \"";
msg += file_name;
msg += "\": ";
msg += toStrerror(errno);
mxml_strlcpy(error, msg.c_str(), error_size);
return NULL; return NULL;
} }
/* read complete file at once */ /* read complete file at once */
int rd = read(fh, buf, length); length = (int)read(fh, buf, length);
if (rd != length) {
std::string msg = "";
msg += "Cannot read file \"";
msg += file_name;
msg += "\", read of ";
msg += toString(length);
msg += " returned ";
msg += toString(rd);
msg += ": ";
msg += toStrerror(errno);
mxml_strlcpy(error, msg.c_str(), error_size);
mxml_free(buf);
return NULL;
}
buf[length] = 0; buf[length] = 0;
close(fh); close(fh);
@ -2126,7 +2042,7 @@ PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, i
return NULL; return NULL;
} }
PMXML_NODE root = mxml_parse_buffer(buf, error, error_size, error_line); root = mxml_parse_buffer(buf, error, error_size, error_line);
mxml_free(buf); mxml_free(buf);
@ -2186,47 +2102,12 @@ int mxml_write_tree(const char *file_name, PMXML_NODE tree)
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/**
* write a complete XML tree to a buffer
*/
int mxml_print_tree(char *buffer, int *buffer_size, PMXML_NODE tree)
{
int len;
char *p;
MXML_WRITER *writer;
/* open file */
writer = mxml_open_buffer();
if (writer == NULL)
return FALSE;
for (int i=0 ; i<tree->n_children ; i++)
if (tree->child[i].node_type == ELEMENT_NODE) /* skip PI and comments */
if (!mxml_write_subtree(writer, &tree->child[i], TRUE))
return FALSE;
p = mxml_close_buffer(writer);
len = strlen(p) + 1;
if (len > *buffer_size) {
free(p);
*buffer_size = 0;
return FALSE;
}
mxml_strlcpy(buffer, p, *buffer_size);
free(p);
*buffer_size = len;
return TRUE;
}
/*------------------------------------------------------------------*/
PMXML_NODE mxml_clone_tree(PMXML_NODE tree) PMXML_NODE mxml_clone_tree(PMXML_NODE tree)
{ {
PMXML_NODE clone; PMXML_NODE clone;
int i; int i;
clone = (PMXML_NODE)calloc(1, sizeof(MXML_NODE)); clone = (PMXML_NODE)calloc(sizeof(MXML_NODE), 1);
/* copy name, node_type, n_attributes and n_children */ /* copy name, node_type, n_attributes and n_children */
memcpy(clone, tree, sizeof(MXML_NODE)); memcpy(clone, tree, sizeof(MXML_NODE));
@ -2423,7 +2304,7 @@ void mxml_dirname(char *path)
if (p == 0) /* current directory */ if (p == 0) /* current directory */
strcpy(path, "."); strcpy(path, ".");
else if (p == path) /* root directory */ else if (p == path) /* root directory */
snprintf(path, FILENAME_MAX, "%c", *p); sprintf(path, "%c", *p);
else else
*p = 0; *p = 0;
@ -2452,10 +2333,3 @@ PMXML_NODE mxml_get_node_at_line(PMXML_NODE tree, int line_number)
return NULL; return NULL;
} }
/* emacs
* Local Variables:
* tab-width: 8
* c-basic-offset: 3
* indent-tabs-mode: nil
* End:
*/

14
mxml.h
View File

@ -38,7 +38,7 @@
#define INTERNAL_ENTITY 0 #define INTERNAL_ENTITY 0
#define EXTERNAL_ENTITY 1 #define EXTERNAL_ENTITY 1
#define MXML_MAX_ENTITY 50 #define MXML_MAX_ENTITY 500
#define MXML_MAX_CONDITION 10 #define MXML_MAX_CONDITION 10
@ -78,6 +78,11 @@ typedef struct mxml_struct {
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* make functions callable from a C++ program */
#ifdef __cplusplus
extern "C" {
#endif
#ifndef EXPRT #ifndef EXPRT
#if defined(EXPORT_DLL) #if defined(EXPORT_DLL)
#define EXPRT __declspec(dllexport) #define EXPRT __declspec(dllexport)
@ -136,13 +141,16 @@ PMXML_NODE mxml_create_root_node(void);
PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line); PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line);
PMXML_NODE mxml_parse_buffer(const char *buffer, char *error, int error_size, int *error_line); PMXML_NODE mxml_parse_buffer(const char *buffer, char *error, int error_size, int *error_line);
int mxml_parse_entity(char **buf, const char* file_name, char *error, int error_size, int *error_line); int mxml_parse_entity(char **buf, const char* file_name, char *error, int error_size, int *error_line);
int mxml_print_tree(char *buffer, int *buffer_size, PMXML_NODE tree); int mxml_write_tree(const char *file_name, PMXML_NODE tree);
void mxml_debug_tree(PMXML_NODE tree, int level); void mxml_debug_tree(PMXML_NODE tree, int level);
void mxml_free_tree(PMXML_NODE tree); void mxml_free_tree(PMXML_NODE tree);
int mxml_write_tree(const char *file_name, PMXML_NODE tree);
void mxml_dirname(char* path); void mxml_dirname(char* path);
void mxml_basename(char *path); void mxml_basename(char *path);
#ifdef __cplusplus
}
#endif
#endif /* _MXML_H_ */ #endif /* _MXML_H_ */
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/

101
strlcpy.c Normal file
View File

@ -0,0 +1,101 @@
/********************************************************************\
Name: strlcpy.c
Created by: Stefan Ritt
Copyright 2000 + Stefan Ritt
Contents: Contains strlcpy and strlcat which are versions of
strcpy and strcat, but which avoid buffer overflows
This file is part of MIDAS XML Library.
MIDAS XML Library 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.
MIDAS XML Library 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 MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>.
\********************************************************************/
#include <stdio.h>
#include <string.h>
#include "strlcpy.h"
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless size == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
#ifndef STRLCPY_DEFINED
size_t strlcpy(char *dst, const char *src, size_t size)
{
char *d = dst;
const char *s = src;
size_t n = size;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (size != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++);
}
return (s - src - 1); /* count does not include NUL */
}
/*-------------------------------------------------------------------*/
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless size <= strlen(dst)).
* Returns strlen(src) + MIN(size, strlen(initial dst)).
* If retval >= size, truncation occurred.
*/
size_t strlcat(char *dst, const char *src, size_t size)
{
char *d = dst;
const char *s = src;
size_t n = size;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = size - dlen;
if (n == 0)
return (dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return (dlen + (s - src)); /* count does not include NUL */
}
/*-------------------------------------------------------------------*/
#endif // STRLCPY_DEFINED

55
strlcpy.h Normal file
View File

@ -0,0 +1,55 @@
/********************************************************************\
Name: strlcpy.h
Created by: Stefan Ritt
Copyright 2000 + Stefan Ritt
Contents: Header file for strlcpy.c
This file is part of MIDAS XML Library.
MIDAS XML Library 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.
MIDAS XML Library 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 MIDAS XML Library. If not, see <http://www.gnu.org/licenses/>.
\********************************************************************/
#ifndef _STRLCPY_H_
#define _STRLCPY_H_
// some version of gcc have a built-in strlcpy
#ifdef strlcpy
#define STRLCPY_DEFINED
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef EXPRT
#if defined(EXPORT_DLL)
#define EXPRT __declspec(dllexport)
#else
#define EXPRT
#endif
#endif
#ifndef STRLCPY_DEFINED
size_t EXPRT strlcpy(char *dst, const char *src, size_t size);
size_t EXPRT strlcat(char *dst, const char *src, size_t size);
#endif
#ifdef __cplusplus
}
#endif
#endif /*_STRLCPY_H_ */