init
This commit is contained in:
commit
32ef62bd20
11 changed files with 2354 additions and 0 deletions
168
src/core.c
Normal file
168
src/core.c
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
#include <xmllib.h>
|
||||
|
||||
#include "../external/stb_ds.h"
|
||||
|
||||
xmllib_t* xmllib_open(xmllib_driver_t* driver, void* arg) {
|
||||
xmllib_t* handle = malloc(sizeof(*handle));
|
||||
memset(handle, 0, sizeof(*handle));
|
||||
|
||||
handle->driver = driver;
|
||||
handle->drv_arg = arg;
|
||||
|
||||
if(!handle->driver->open(handle)) {
|
||||
free(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
enum STATES {
|
||||
STATE_INITIAL = 0,
|
||||
STATE_TAG,
|
||||
STATE_STRING,
|
||||
STATE_SPECIAL,
|
||||
STATE_COMMENT,
|
||||
STATE_DOCTYPE,
|
||||
};
|
||||
|
||||
#define TAKE_AS_NODE(x) \
|
||||
{ \
|
||||
char* old = node; \
|
||||
char buf[4]; \
|
||||
int new = xmllib_unicode_32_to_8((x), buf); \
|
||||
\
|
||||
node = malloc(strlen(old) + new + 1); \
|
||||
strcpy(node, old); \
|
||||
memcpy(node + strlen(old), buf, new); \
|
||||
node[strlen(old) + new] = 0; \
|
||||
node_count++; \
|
||||
}
|
||||
|
||||
#define CLEANUP \
|
||||
{ \
|
||||
if(node != NULL) free(node); \
|
||||
arrfree(state); \
|
||||
}
|
||||
|
||||
#define ERROR \
|
||||
{ \
|
||||
printf("%d\n", __LINE__); \
|
||||
CLEANUP; \
|
||||
longjmp(err, 1); \
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
if(setjmp(err)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
arrput(state, STATE_INITIAL);
|
||||
|
||||
while(1) {
|
||||
char in[4];
|
||||
int c;
|
||||
int cp;
|
||||
|
||||
if(handle->driver->read(handle, &in[0], 1) < 1) ERROR;
|
||||
|
||||
c = xmllib_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);
|
||||
|
||||
if(cp == '<' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) {
|
||||
if(STATE == STATE_INITIAL) {
|
||||
arrput(state, STATE_TAG);
|
||||
|
||||
node = malloc(1);
|
||||
node[0] = 0;
|
||||
node_count = 0;
|
||||
} else if(STATE == STATE_STRING) {
|
||||
TAKE_AS_NODE(cp);
|
||||
} 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] == ']')) {
|
||||
arrpop(state);
|
||||
|
||||
if(STATE == STATE_INITIAL) {
|
||||
/* parsed tag */
|
||||
|
||||
if(node[0] == '!') {
|
||||
/* special tag */
|
||||
if(strlen(node) > 1 && node[1] == '-') {
|
||||
/* comment */
|
||||
} else {
|
||||
/* doctype or something - we ignore this for now */
|
||||
}
|
||||
} else if(node[0] == '?') {
|
||||
/* process */
|
||||
} else {
|
||||
/* normal tag */
|
||||
if(node[0] == '/') {
|
||||
/* close tag */
|
||||
|
||||
nest_level--;
|
||||
} else if(node[strlen(node) - 1] == '/') {
|
||||
/* self-closing tag */
|
||||
|
||||
nest_level++;
|
||||
}
|
||||
|
||||
if(nest_level < 0) ERROR;
|
||||
if(nest_level == 0) break;
|
||||
}
|
||||
|
||||
free(node);
|
||||
node = NULL;
|
||||
}
|
||||
} else {
|
||||
TAKE_AS_NODE(cp);
|
||||
}
|
||||
} else if(STATE == STATE_STRING) {
|
||||
TAKE_AS_NODE(cp);
|
||||
} else {
|
||||
ERROR;
|
||||
}
|
||||
} else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) {
|
||||
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) {
|
||||
if(node_count == 0 && cp == '!') {
|
||||
arrpop(state);
|
||||
arrput(state, STATE_SPECIAL);
|
||||
} else if(node_count == 1 && STATE == STATE_SPECIAL && cp == '-') {
|
||||
arrpop(state);
|
||||
arrput(state, STATE_COMMENT);
|
||||
} else if(node_count == 1 && STATE == STATE_SPECIAL) {
|
||||
arrpop(state);
|
||||
arrput(state, STATE_DOCTYPE);
|
||||
}
|
||||
TAKE_AS_NODE(cp);
|
||||
}
|
||||
}
|
||||
|
||||
CLEANUP;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void xmllib_close(xmllib_t* handle) {
|
||||
handle->driver->close(handle);
|
||||
free(handle);
|
||||
}
|
||||
26
src/file.c
Normal file
26
src/file.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include <xmllib.h>
|
||||
|
||||
static int xmllib_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) {
|
||||
return fread(data, 1, size, handle->drv_opaque);
|
||||
}
|
||||
|
||||
static void xmllib_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,
|
||||
};
|
||||
xmllib_driver_t* xmllib_driver_file = &xmllib_driver_file_rec;
|
||||
|
||||
xmllib_t* xmllib_open_file(const char* filename) {
|
||||
return xmllib_open(xmllib_driver_file, (void*)filename);
|
||||
}
|
||||
2
src/stb_ds.c
Normal file
2
src/stb_ds.c
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define STB_DS_IMPLEMENTATION
|
||||
#include "../external/stb_ds.h"
|
||||
79
src/unicode.c
Normal file
79
src/unicode.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include <xmllib.h>
|
||||
|
||||
#define CAST_I32(x) ((int)(x))
|
||||
|
||||
int xmllib_unicode_count(unsigned char c) {
|
||||
if(c < 0x80) {
|
||||
return 1;
|
||||
}
|
||||
if(0xc2 <= c && c < 0xe0) {
|
||||
return 2;
|
||||
}
|
||||
if(0xe0 <= c && c < 0xf0) {
|
||||
return 3;
|
||||
}
|
||||
if(0xf0 <= c && c < 0xf8) {
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unicode_later(unsigned char c) {
|
||||
return 0x80 <= c && c < 0xc0;
|
||||
}
|
||||
|
||||
int xmllib_unicode_8_to_32(const char* input, int* output) {
|
||||
const unsigned char* inbuf = (const unsigned char*)input;
|
||||
int b = xmllib_unicode_count(inbuf[0]);
|
||||
if(b == 0) return 0;
|
||||
|
||||
if(b == 1) *output = inbuf[0];
|
||||
if(b == 2) {
|
||||
if(!unicode_later(inbuf[1])) return 0;
|
||||
if((inbuf[0] & 0x1e) == 0) return 0;
|
||||
|
||||
*output = CAST_I32(inbuf[0] & 0x1f) << 6;
|
||||
*output |= CAST_I32(inbuf[1] & 0x3f);
|
||||
}
|
||||
if(b == 3) {
|
||||
if(!unicode_later(inbuf[1]) || !unicode_later(inbuf[2])) return 0;
|
||||
if((inbuf[0] & 0x0f) == 0 && (inbuf[1] & 0x20) == 0) return 0;
|
||||
|
||||
*output = CAST_I32(inbuf[0] & 0x0f) << 12;
|
||||
*output |= CAST_I32(inbuf[1] & 0x3f) << 6;
|
||||
*output |= CAST_I32(inbuf[2] & 0x3f);
|
||||
}
|
||||
if(b == 4) {
|
||||
if(!unicode_later(inbuf[1]) || !unicode_later(inbuf[2]) || !unicode_later(inbuf[3])) return 0;
|
||||
if((inbuf[0] & 0x07) == 0 && (inbuf[1] & 0x30) == 0) return 0;
|
||||
|
||||
*output = CAST_I32(inbuf[0] & 0x07) << 18;
|
||||
*output |= CAST_I32(inbuf[1] & 0x3f) << 12;
|
||||
*output |= CAST_I32(inbuf[2] & 0x3f) << 6;
|
||||
*output |= CAST_I32(inbuf[3] & 0x3f);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
int xmllib_unicode_32_to_8(const int input, char* output) {
|
||||
if(input < 128) {
|
||||
output[0] = input;
|
||||
return 1;
|
||||
} else if(input < 2048) {
|
||||
output[0] = 0xc0 | (input >> 6);
|
||||
output[1] = 0x80 | (input & 0x3f);
|
||||
return 2;
|
||||
} else if(input < 65536) {
|
||||
output[0] = 0xe0 | (input >> 12);
|
||||
output[1] = 0x80 | ((input >> 6) & 0x3f);
|
||||
output[2] = 0x80 | (input & 0x3f);
|
||||
return 3;
|
||||
} else {
|
||||
output[0] = 0xf0 | (input >> 18);
|
||||
output[1] = 0x80 | ((input >> 12) & 0x3f);
|
||||
output[2] = 0x80 | ((input >> 6) & 0x3f);
|
||||
output[3] = 0x80 | (input & 0x3f);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue