cdata works

This commit is contained in:
Nishi 2025-12-22 20:44:41 +09:00
commit 1113b2dbe3
Signed by: nishi
GPG key ID: 27EF69B208EB9343
7 changed files with 196 additions and 126 deletions

View file

@ -2,7 +2,7 @@
#include "../external/stb_ds.h"
xmllib_t* xmllib_open(xmllib_driver_t* driver, void* arg) {
xmllib_t* xl_open(xl_driver_t* driver, void* arg) {
xmllib_t* handle = malloc(sizeof(*handle));
memset(handle, 0, sizeof(*handle));
@ -23,14 +23,15 @@ enum STATES {
STATE_STRING,
STATE_SPECIAL,
STATE_COMMENT,
STATE_DOCTYPE,
STATE_MISC,
STATE_IGNORE_TAG
};
#define TAKE_AS_NODE(x) \
{ \
char* old = node; \
char buf[4]; \
int new = xmllib_unicode_32_to_8((x), &buf[0]); \
int new = xl_unicode_32_to_8((x), &buf[0]); \
\
node = malloc(strlen(old) + new + 1); \
strcpy(node, old); \
@ -54,17 +55,15 @@ enum STATES {
longjmp(err, 1); \
}
#define SKIPPABLE(x) (((x) == ' ') || ((x) == '\t') || ((x) == '\n') || ((x) == '\r'))
#define STATE state[arrlen(state) - 1]
int xmllib_parse(xmllib_t* handle) {
jmp_buf err;
int* state = NULL;
char* node = NULL;
int node_count = 0;
int nest_level = 0;
xmllib_node_t* current = NULL;
int xl_parse(xmllib_t* handle) {
jmp_buf err;
int* state = NULL;
char* node = NULL;
int node_count = 0;
int nest_level = 0;
xl_node_t* current = NULL;
if(setjmp(err)) {
return 0;
@ -79,12 +78,12 @@ int xmllib_parse(xmllib_t* handle) {
if(handle->driver->read(handle, &in[0], 1) < 1) ERROR;
c = xmllib_unicode_count(in[0]);
c = xl_unicode_count(in[0]);
if((c > 1) && handle->driver->read(handle, &in[1], c - 1) < (c - 1)) longjmp(err, 1);
xmllib_unicode_8_to_32(in, &cp);
xl_unicode_8_to_32(in, &cp);
if(cp == '<' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) {
if(cp == '<' && STATE != STATE_COMMENT) {
if(STATE == STATE_INITIAL) {
arrput(state, STATE_TAG);
@ -93,34 +92,51 @@ int xmllib_parse(xmllib_t* handle) {
node_count = 0;
} else if(STATE == STATE_STRING) {
TAKE_AS_NODE(cp);
} else if(STATE == STATE_MISC) {
arrput(state, STATE_IGNORE_TAG);
} else {
ERROR;
}
} else if(cp == '>') {
if(STATE == STATE_TAG || STATE == STATE_DOCTYPE || STATE == STATE_COMMENT) {
if((STATE != STATE_COMMENT || node[strlen(node) - 1] == '-') && (STATE != STATE_DOCTYPE || node[strlen(node) - 1] == ']')) {
if(STATE == STATE_TAG || STATE == STATE_COMMENT || STATE == STATE_MISC || STATE == STATE_IGNORE_TAG) {
if((STATE != STATE_COMMENT || node[strlen(node) - 1] == '-')) {
arrpop(state);
if(STATE == STATE_INITIAL) {
/* parsed tag */
xmllib_node_t* n = NULL;
xmllib_node_t* targ = NULL;
xl_node_t* n = NULL;
xl_node_t* targ = NULL;
if(node[0] == '!') {
/* special tag */
if(strlen(node) > 1 && node[1] == '-') {
if(strlen(node) > 2 && node[1] == '-') {
/* comment */
if(strlen(node) > (3 + 2) && nest_level > 0) {
if(strlen(node) > (1 + 3 + 2) && nest_level > 0) {
n = malloc(sizeof(*n));
n->type = XMLLIB_NODE_COMMENT;
n->type = XL_NODE_COMMENT;
n->name = NULL;
n->text = malloc(strlen(node) + 1);
strcpy(n->text, node + 3);
n->text[strlen(n->text) - 2] = 0;
}
} else if(strlen(node) > 8 && memcmp(&node[1], "[CDATA[", 7) == 0 && node[strlen(node) - 1] == ']' && node[strlen(node) - 2] == ']') {
char* old = current->text;
if(old == NULL) {
current->text = malloc(strlen(node));
strcpy(current->text, node + 8);
} else {
current->text = malloc(strlen(old) + strlen(node));
strcpy(current->text, old);
strcpy(current->text + strlen(old), node + 8);
free(old);
}
if(strlen(current->text) > 2) {
current->text[strlen(current->text) - 2] = 0;
}
} else {
/* doctype or something - we ignore this for now */
}
@ -130,59 +146,30 @@ int xmllib_parse(xmllib_t* handle) {
/* normal tag */
if(node[0] == '/') {
/* close tag */
char* str;
if(nest_level > 0) {
if(strcmp(current->name, node + 1) != 0) ERROR;
if(current->text != NULL) {
int i, inc;
int* l = NULL;
char* txt = current->text;
i = 0;
while(1) {
int icp;
int nb = xmllib_unicode_8_to_32(txt + i, &icp);
if(icp == 0) break;
arrput(l, nb);
i += nb;
}
inc = strlen(txt);
i = arrlen(l) - 1;
while(1) {
int icp;
int nb;
inc -= l[i];
nb = xmllib_unicode_8_to_32(txt + inc, &icp);
if(SKIPPABLE(icp)) {
txt[inc] = 0;
} else {
break;
}
i--;
}
arrfree(l);
}
targ = current->parent;
}
nest_level--;
str = xl_util_trim(current->text);
free(current->text);
current->text = str;
if(strlen(current->text) == 0) {
free(current->text);
current->text = NULL;
}
} else {
int i;
n = malloc(sizeof(*n));
n->type = XMLLIB_NODE_NODE;
n->type = XL_NODE_NODE;
n->name = malloc(strlen(node) + 1);
n->text = NULL;
@ -190,11 +177,11 @@ int xmllib_parse(xmllib_t* handle) {
i = 0;
while(1) {
int icp;
int nb = xmllib_unicode_8_to_32(n->name + i, &icp);
int nb = xl_unicode_8_to_32(n->name + i, &icp);
if(icp == 0) break;
if(SKIPPABLE(icp)) {
if(XL_SKIPPABLE(icp)) {
n->name[i] = 0;
break;
}
@ -214,7 +201,7 @@ int xmllib_parse(xmllib_t* handle) {
}
if(n != NULL) {
xmllib_node_t* last = NULL;
xl_node_t* last = NULL;
if(handle->root == NULL) handle->root = n;
@ -253,14 +240,14 @@ int xmllib_parse(xmllib_t* handle) {
} else {
ERROR;
}
} else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) {
} else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_MISC) {
if(STATE == STATE_TAG) {
arrput(state, STATE_STRING);
} else if(STATE == STATE_STRING) {
arrpop(state);
}
TAKE_AS_NODE(cp);
} else if(STATE == STATE_TAG || STATE == STATE_STRING || STATE == STATE_SPECIAL || STATE == STATE_COMMENT || STATE == STATE_DOCTYPE) {
} else if(STATE == STATE_TAG || STATE == STATE_STRING || STATE == STATE_SPECIAL || STATE == STATE_COMMENT || STATE == STATE_MISC || STATE == STATE_IGNORE_TAG) {
if(node_count == 0 && cp == '!') {
arrpop(state);
arrput(state, STATE_SPECIAL);
@ -269,7 +256,7 @@ int xmllib_parse(xmllib_t* handle) {
arrput(state, STATE_COMMENT);
} else if(node_count == 1 && STATE == STATE_SPECIAL) {
arrpop(state);
arrput(state, STATE_DOCTYPE);
arrput(state, STATE_MISC);
}
TAKE_AS_NODE(cp);
} else if(STATE == STATE_INITIAL) {
@ -277,7 +264,7 @@ int xmllib_parse(xmllib_t* handle) {
char* old = current->text;
if(old != NULL) {
char buf[4];
int new = xmllib_unicode_32_to_8(cp, &buf[0]);
int new = xl_unicode_32_to_8(cp, &buf[0]);
current->text = malloc(strlen(old) + new + 1);
strcpy(current->text, old);
@ -285,9 +272,9 @@ int xmllib_parse(xmllib_t* handle) {
current->text[strlen(old) + new] = 0;
free(old);
} else if(!SKIPPABLE(cp)) {
} else {
char buf[4];
int new = xmllib_unicode_32_to_8(cp, &buf[0]);
int new = xl_unicode_32_to_8(cp, &buf[0]);
current->text = malloc(new + 1);
memcpy(current->text, &buf[0], new);
@ -304,8 +291,8 @@ int xmllib_parse(xmllib_t* handle) {
return 1;
}
void recursive_free(xmllib_node_t* node) {
xmllib_node_t* n = node->first_child;
void recursive_free(xl_node_t* node) {
xl_node_t* n = node->first_child;
while(n != NULL) {
recursive_free(n);
@ -317,8 +304,8 @@ void recursive_free(xmllib_node_t* node) {
free(node);
}
void xmllib_close(xmllib_t* handle) {
recursive_free(handle->root);
void xl_close(xmllib_t* handle) {
if(handle->root != NULL) recursive_free(handle->root);
handle->driver->close(handle);
free(handle);

View file

@ -1,26 +1,26 @@
#include <xmllib.h>
static int xmllib_driver_file_open(xmllib_t* handle) {
static int xl_driver_file_open(xmllib_t* handle) {
if((handle->drv_opaque = fopen(handle->drv_arg, "rb")) == NULL) return 0;
return 1;
}
static int xmllib_driver_file_read(xmllib_t* handle, void* data, int size) {
static int xl_driver_file_read(xmllib_t* handle, void* data, int size) {
return fread(data, 1, size, handle->drv_opaque);
}
static void xmllib_driver_file_close(xmllib_t* handle) {
static void xl_driver_file_close(xmllib_t* handle) {
fclose(handle->drv_opaque);
}
xmllib_driver_t xmllib_driver_file_rec = {
xmllib_driver_file_open,
xmllib_driver_file_read,
xmllib_driver_file_close,
xl_driver_t xl_driver_file_rec = {
xl_driver_file_open,
xl_driver_file_read,
xl_driver_file_close,
};
xmllib_driver_t* xmllib_driver_file = &xmllib_driver_file_rec;
xl_driver_t* xl_driver_file = &xl_driver_file_rec;
xmllib_t* xmllib_open_file(const char* filename) {
return xmllib_open(xmllib_driver_file, (void*)filename);
xmllib_t* xl_open_file(const char* filename) {
return xl_open(xl_driver_file, (void*)filename);
}

View file

@ -2,7 +2,7 @@
#define CAST_I32(x) ((int)(x))
int xmllib_unicode_count(unsigned char c) {
int xl_unicode_count(unsigned char c) {
if(c < 0x80) {
return 1;
}
@ -22,9 +22,9 @@ static int unicode_later(unsigned char c) {
return 0x80 <= c && c < 0xc0;
}
int xmllib_unicode_8_to_32(const char* input, int* output) {
int xl_unicode_8_to_32(const char* input, int* output) {
const unsigned char* inbuf = (const unsigned char*)input;
int b = xmllib_unicode_count(inbuf[0]);
int b = xl_unicode_count(inbuf[0]);
if(b == 0) return 0;
if(b == 1) *output = inbuf[0];
@ -56,7 +56,7 @@ int xmllib_unicode_8_to_32(const char* input, int* output) {
return b;
}
int xmllib_unicode_32_to_8(const int input, char* output) {
int xl_unicode_32_to_8(const int input, char* output) {
if(input < 128) {
output[0] = input;
return 1;

78
src/util.c Normal file
View file

@ -0,0 +1,78 @@
#include <xmllib.h>
#include "../external/stb_ds.h"
char* xl_util_trim(const char* str) {
char* s = malloc(strlen(str) + 1);
int nl = 1;
int i;
int inc = 0;
int* l = NULL;
s[0] = 0;
i = 0;
while(1) {
int cp;
int new = xl_unicode_8_to_32(str + i, &cp);
int len = 0;
char buf[4];
if(cp == 0) break;
if(!nl && cp == '\n') {
len = xl_unicode_32_to_8(cp, &buf[0]);
nl = 1;
} else if(nl && XL_SKIPPABLE(cp)) {
} else {
len = xl_unicode_32_to_8(cp, &buf[0]);
nl = 0;
}
if(len > 0) {
memcpy(s + inc, buf, len);
inc += len;
}
i += new;
}
s[inc] = 0;
i = 0;
while(1) {
int cp;
int new = xl_unicode_8_to_32(s + i, &cp);
if(cp == 0) break;
arrput(l, new);
i += new;
}
i = strlen(s);
inc = arrlen(l) - 1;
if(inc > 0) {
while(1) {
int cp, new;
i -= l[inc];
new = xl_unicode_8_to_32(s + i, &cp);
if(XL_SKIPPABLE(cp)) {
s[i] = 0;
} else {
break;
}
inc--;
if(inc < 0) break;
}
}
arrfree(l);
return s;
}