eebie/schemagen/schemagen.c
2024-07-25 10:52:05 +03:00

151 lines
5.8 KiB
C

#include<stdio.h>
#include"ezxml.h"
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char **argv) {
ezxml_t schema = ezxml_parse_file(argv[1]);
char *Name = strdup(argv[2]);
char *NAME = strdup(Name);
for(char *c = NAME; *c; c++) {
*c = toupper(*c);
}
char *name = strdup(Name);
for(char *c = name; *c; c++) {
*c = tolower(*c);
}
printf("#ifndef %s_PARSER_H\n", NAME);
printf("#define %s_PARSER_H\n", NAME);
printf("#include<stdint.h>\n");
printf("#include<stddef.h>\n");
printf("#include<stdlib.h>\n");
printf("#include<string.h>\n");
printf("#include\"eebie/reader.h\"\n");
for(ezxml_t el = ezxml_child(schema, "element"); el; el = el->next) {
printf("#define %s_%s %sL\n", NAME, ezxml_attr(el, "name"), ezxml_attr(el, "id"));
}
printf("typedef struct %sParser {\n", Name);
printf("\tvoid *ud;\n");
printf("\tuint8_t *accum;\n");
printf("\tsize_t accumLen;\n");
printf("\tEBMLReader ebml;\n");
for(ezxml_t el = ezxml_child(schema, "element"); el; el = el->next) {
const char *type = ezxml_attr(el, "type");
if(!strcmp(type, "master")) {
printf("\tvoid(*On%s)(struct %sParser*);\n", ezxml_attr(el, "name"), Name);
} else if(!strcmp(type, "uinteger")) {
printf("\tvoid(*On%s)(struct %sParser*, uint64_t value);\n", ezxml_attr(el, "name"), Name);
} else if(!strcmp(type, "integer")) {
printf("\tvoid(*On%s)(struct %sParser*, int64_t value);\n", ezxml_attr(el, "name"), Name);
} else if(!strcmp(type, "date")) {
printf("\tvoid(*On%s)(struct %sParser*, int64_t value);\n", ezxml_attr(el, "name"), Name);
} else if(!strcmp(type, "float")) {
printf("\tvoid(*On%s)(struct %sParser*, double value);\n", ezxml_attr(el, "name"), Name);
} else {
if(strcmp(type, "binary") && strcmp(type, "utf-8") && strcmp(type, "string")) {
fprintf(stderr, "Interpreting unknown element type \"%s\" as binary\n", type);
}
printf("\tvoid(*On%s)(struct %sParser*, const uint8_t *data, size_t length);\n", ezxml_attr(el, "name"), Name);
}
}
printf("} %sParser;\n", Name);
printf("void %s_parser_init(%sParser*);\n", name, Name);
printf("size_t %s_parser_feed(%sParser*, const uint8_t *data, size_t length);\n", name, Name);
printf("#ifdef %s_PARSER_IMPLEMENTATION\n", NAME);
printf("EBMLElementType %s_event_enter_element(EBMLReader *rdr, uint64_t id, uint64_t length) {\n", name);
printf("\t%sParser *self = rdr->ud;\n", Name);
for(ezxml_t el = ezxml_child(schema, "element"); el; el = el->next) {
const char *type = ezxml_attr(el, "type");
if(!strcmp(type, "master")) {
printf("\tif(id == %s_%s) {\n", NAME, ezxml_attr(el, "name"));
printf("\t\tif(self->On%s) self->On%s(self);\n", ezxml_attr(el, "name"), ezxml_attr(el, "name"));
printf("\t\treturn EBML_TREE;\n");
printf("\t}\n");
}
}
printf("\treturn EBML_BINARY;\n");
printf("}\n");
printf("void %s_event_data_chunk(EBMLReader *rdr, const uint8_t *data, uint64_t length) {\n", name);
printf("\t%sParser *self = rdr->ud;\n", Name);
printf("\tself->accum = realloc(self->accum, self->accumLen + length);\n");
printf("\tmemcpy(self->accum + self->accumLen, data, length);\n");
printf("\tself->accumLen += length;\n");
printf("}\n");
printf("void %s_event_exit_element(EBMLReader *rdr) {\n", name);
printf("\t%sParser *self = rdr->ud;\n", Name);
printf("\tuint64_t id = rdr->idStack[rdr->currentDepth - 1];\n");
for(ezxml_t el = ezxml_child(schema, "element"); el; el = el->next) {
const char *type = ezxml_attr(el, "type");
printf("\tif(id == %s_%s) {\n", NAME, ezxml_attr(el, "name"));
if(!strcmp(type, "uinteger") || !strcmp(type, "integer") || !strcmp(type, "date")) {
printf("\t\t%s val = 0;\n", !strcmp(type, "uinteger") ? "uint64_t" : "int64_t");
printf("\t\tmemcpy((uint8_t*) &val + 8 - self->accumLen, self->accum, self->accumLen);\n");
printf("\t\tval = be64toh(val);\n");
printf("\t\tif(self->On%s) self->On%s(self, val);\n", ezxml_attr(el, "name"), ezxml_attr(el, "name"));
} else if(!strcmp(type, "string") || !strcmp(type, "utf-8") || !strcmp(type, "binary")) {
if(strcmp(type, "binary") != 0) {
printf("\t\tself->accum = realloc(self->accum, self->accumLen + 1);\n");
printf("\t\tself->accum[self->accumLen] = 0;\n");
}
printf("\t\tif(self->On%s) self->On%s(self, self->accum, self->accumLen);\n", ezxml_attr(el, "name"), ezxml_attr(el, "name"));
} else if(!strcmp(type, "float")) {
printf("\t\tdouble val;\n");
printf("\t\tif(self->accumLen == 4) {\n");
printf("\t\t\tfloat fval;\n");
printf("\t\t\tmemcpy(&fval, self->accum, 4);\n");
printf("\t\t\t*(uint32_t*) &fval = be32toh(*(uint32_t*) &fval);\n");
printf("\t\t\tval = fval;\n");
printf("\t\t} else {\n");
printf("\t\t\tmemcpy(&val, self->accum, 8);\n");
printf("\t\t\t*(uint64_t*) &val = be64toh(*(uint64_t*) &val);\n");
printf("\t\t}\n");
printf("\t\tif(self->On%s) self->On%s(self, val);\n", ezxml_attr(el, "name"), ezxml_attr(el, "name"));
} else if(!strcmp(type, "master")) {
// Do nothing.
} else {
fprintf(stderr, "Ignoring unknown type \"%s\"\n", type);
}
printf("\t}\n");
}
printf("\tfree(self->accum); self->accum = NULL; self->accumLen = 0;\n");
printf("}\n");
printf("void %s_parser_init(%sParser *self) {\n", name, Name);
printf("\tmemset(self, 0, sizeof(*self));\n");
printf("\tebml_reader_init(&self->ebml);\n");
printf("\tself->ebml.eventEnterElement = %s_event_enter_element;\n", name);
printf("\tself->ebml.eventDataChunk = %s_event_data_chunk;\n", name);
printf("\tself->ebml.eventExitElement = %s_event_exit_element;\n", name);
printf("\tself->ebml.ud = self;\n");
printf("}\n");
printf("size_t %s_parser_feed(%sParser *self, const uint8_t *data, size_t length) {\n", name, Name);
printf("\treturn ebml_reader_feed(&self->ebml, data, length);\n");
printf("}\n");
printf("#endif\n");
printf("#endif\n");
}