From 1a8f91467aad191721d57a9ad772f6700c029e1d Mon Sep 17 00:00:00 2001 From: P. J. McDermott Date: Sun, 17 Feb 2013 01:20:49 -0500 Subject: TMX parser rewrite number two. --- (limited to 'src/resources/map.c') diff --git a/src/resources/map.c b/src/resources/map.c index b703629..6e5606b 100644 --- a/src/resources/map.c +++ b/src/resources/map.c @@ -4,420 +4,393 @@ #include #include "map.h" #include "resource.h" -#include "tileset.h" #include "../xml.h" #include "../logging.h" -struct tmx { - XML_Parser p; - struct map *map; - char *layer_data; -}; - +struct resource_table ts_res; struct resource_table map_res; -static void XMLCALL xml_map_start(void *data, const char *el, - const char **attr); -static void XMLCALL xml_map_end(void *data, const char *el); -static void XMLCALL xml_mapelem_start(void *data, const char *el, - const char **attr); -static void XMLCALL xml_mapelem_end(void *data, const char *el); -static void XMLCALL xml_image_start(void *data, const char *el, - const char **attr); -static void XMLCALL xml_image_end(void *data, const char *el); -static void XMLCALL xml_data_start(void *data, const char *el, - const char **attr); -static void XMLCALL xml_data_data(void *data, const char *s, int len); -static void XMLCALL xml_data_end(void *data, const char *el); -static void XMLCALL xml_object_start(void *data, const char *el, - const char **attr); -static void XMLCALL xml_object_end(void *data, const char *el); - -void map_add_layer(struct map *m, struct layer *l); -void map_add_tileset(struct map *m, struct tileset *t); +static struct tileset *tileset_get(const char *); +static void XMLCALL tmx_map_start(void *, const char *, const char **); +static void XMLCALL tmx_map_end(void *, const char *); +static void XMLCALL tmx_map_el_start(void *, const char *, const char **); +static void XMLCALL tmx_tileset_start(void *, const char *, const char **); +static void XMLCALL tmx_tileset_end(void *, const char *); +static void XMLCALL tmx_ext_ts_end(void *, const char *); +static void XMLCALL tmx_tileset_el_start(void *, const char *, const char **); +static void XMLCALL tmx_image_end(void *, const char *); +static void XMLCALL tmx_unused_start(void *, const char *, const char **); +static void XMLCALL tmx_unused_end(void *, const char *); +static void XMLCALL tmx_invalid_start(void *, const char *, const char **); +static void XMLCALL tmx_invalid_end(void *, const char *); -static void XMLCALL -xml_map_start(void *data, const char *el, const char **attr) +struct map * +map_get(const char *path) { - struct tmx *tmx; + struct map *map; + XML_Parser p; + FILE *tmx_fp; + void *tmx_buf; + size_t len; + enum XML_Status status; - debug("<%s> (type \"map\")", el); + map = (struct map *) resource_get(&map_res, path); + if (map != NULL) { + resource_use((struct resource *) map); + return map; + } + + p = XML_ParserCreate(NULL); + if (p == NULL) { + warn("Failed to create TMX parser"); + return NULL; + } - tmx = (struct tmx *) data; + XML_UseParserAsHandlerArg(p); + xml_node_push(p, map, tmx_map_start, tmx_invalid_end, NULL); - if (xml_check_tag(el, "map")) { - if (tmx->map != NULL) { - warn("Found multiple maps in TMX file"); - XML_StopParser(tmx->p, XML_FALSE); - } - tmx->map = malloc(sizeof(*tmx->map)); - if (tmx->map == NULL) { - warn("Failed to allocate map"); - XML_StopParser(tmx->p, XML_FALSE); + tmx_fp = fopen(path, "rb"); + if (tmx_fp == NULL) { + warn("Failed to open TMX file"); + xml_node_pop(p); + XML_ParserFree(p); + return NULL; + } + + tmx_buf = XML_GetBuffer(p, 8192); + if (tmx_buf == NULL) { + warn("Failed to create TMX parse buffer"); + xml_node_pop(p); + XML_ParserFree(p); + fclose(tmx_fp); + return NULL; + } + + while (!feof(tmx_fp)) { + len = fread(tmx_buf, 1, 8192, tmx_fp); + status = XML_ParseBuffer(p, len, feof(tmx_fp)); + if (status == XML_STATUS_OK) { + continue; } - memset(tmx->map, 0, sizeof(*tmx->map)); - xml_get_int_attr(tmx->p, attr, "width", - &tmx->map->width, 1); - xml_get_int_attr(tmx->p, attr, "width", - &tmx->map->width, 1); - xml_get_int_attr(tmx->p, attr, "tilewidth", - &tmx->map->tilewidth, 1); - xml_get_int_attr(tmx->p, attr, "tileheight", - &tmx->map->tileheight, 1); - XML_SetStartElementHandler(tmx->p, xml_mapelem_start); - XML_SetEndElementHandler(tmx->p, xml_map_end); - } else { - xml_unexpected_start_tag(tmx->p, el, - "map"); + warn("Failed to parse TMX file (%s)", + XML_ErrorString(XML_GetErrorCode(p))); + xml_node_pop(p); + XML_ParserFree(p); + fclose(tmx_fp); + return NULL; } -} -static void XMLCALL -xml_map_end(void *data, const char *el) -{ - struct tmx *tmx; + map = (struct map *) xml_node_pop(p); + XML_ParserFree(p); + fclose(tmx_fp); - debug(" (type \"map\")", el); + resource_use((struct resource *) map); + resource_add(&map_res, path, (struct resource *) map); - tmx = (struct tmx *) data; + return map; +} - if (xml_check_tag(el, "map")) { - XML_SetStartElementHandler(tmx->p, NULL); - XML_SetEndElementHandler(tmx->p, NULL); +void +map_add_layer(struct map *m, struct layer *l) +{ + if (m->layers_head == NULL) { + m->layers_head = l; } else { - xml_unexpected_end_tag(tmx->p, el, - "map"); + m->layers_tail->next = l; } + m->layers_tail = l; } -static void XMLCALL -xml_mapelem_start(void *data, const char *el, const char **attr) +void +map_add_tileset(struct map *m, struct tileset *t) +{ + if (m->tilesets_head == NULL) { + m->tilesets_head = t; + } else { + m->tilesets_tail->next = t; + } + m->tilesets_tail = t; +} + +static struct tileset * +tileset_get(const char *path) { - struct tmx *tmx; - char *source; struct tileset *ts; - struct layer *ly; + XML_Parser p; + FILE *tmx_fp; + void *tmx_buf; + size_t len; + enum XML_Status status; - debug("<%s> (type \"mapelem\")", el); + ts = (struct tileset *) resource_get(&ts_res, path); + if (ts != NULL) { + resource_use((struct resource *) ts); + return ts; + } - tmx = (struct tmx *) data; + p = XML_ParserCreate(NULL); + if (p == NULL) { + warn("Failed to create TSX parser"); + return NULL; + } - if (xml_check_tag(el, "tileset")) { - source = NULL; - xml_get_string_attr(tmx->p, attr, "source", - &source, 0); - if (source != NULL) { - ts = tileset_get(source); - free(source); - XML_SetStartElementHandler(tmx->p, NULL); - XML_SetEndElementHandler(tmx->p, xml_tileset_end); - } else { - ts = resource_alloc("", sizeof(*ts)); - xml_get_int_attr(tmx->p, attr, "tilewidth", - &ts->tilewidth, 1); - xml_get_int_attr(tmx->p, attr, "tileheight", - &ts->tileheight, 1); - /* TODO: Change xml_image_start to xml_tselem_start. - * A can contain: - * * Zero or one , - * * Zero or one s, and - * * Zero or more s. */ - XML_SetStartElementHandler(tmx->p, xml_image_start); - XML_SetEndElementHandler(tmx->p, xml_tileset_end); + XML_UseParserAsHandlerArg(p); + xml_node_push(p, ts, tmx_tileset_start, tmx_invalid_end, NULL); + + tmx_fp = fopen(path, "rb"); + if (tmx_fp == NULL) { + warn("Failed to open TSX file"); + xml_node_pop(p); + XML_ParserFree(p); + return NULL; + } + + tmx_buf = XML_GetBuffer(p, 8192); + if (tmx_buf == NULL) { + warn("Failed to create TSX parse buffer"); + xml_node_pop(p); + XML_ParserFree(p); + fclose(tmx_fp); + return NULL; + } + + while (!feof(tmx_fp)) { + len = fread(tmx_buf, 1, 8192, tmx_fp); + status = XML_ParseBuffer(p, len, feof(tmx_fp)); + if (status == XML_STATUS_OK) { + continue; } - xml_get_int_attr(tmx->p, attr, "firstgid", - &ts->firstgid, 1); - xml_get_string_attr(tmx->p, attr, "name", - &ts->name, 1); - map_add_tileset(tmx->map, ts); - } else if (xml_check_tag(el, "layer")) { - ly = resource_alloc("", sizeof(*ly)); - xml_get_string_attr(tmx->p, attr, "name", - &ly->name, 1); - map_add_layer(tmx->map, ly); - XML_SetStartElementHandler(tmx->p, xml_data_start); - XML_SetEndElementHandler(tmx->p, xml_mapelem_end); - } else if (xml_check_tag(el, "objectgroup")) { - XML_SetStartElementHandler(tmx->p, xml_object_start); - XML_SetEndElementHandler(tmx->p, xml_mapelem_end); - } else { - xml_unexpected_start_tag(tmx->p, el, - "tileset, layer, or objectgroup"); + warn("Failed to parse TSX file (%s)", + XML_ErrorString(XML_GetErrorCode(p))); + xml_node_pop(p); + XML_ParserFree(p); + fclose(tmx_fp); + return NULL; } + + ts = (struct tileset *) xml_node_pop(p); + XML_ParserFree(p); + fclose(tmx_fp); + + resource_use((struct resource *) ts); + resource_add(&ts_res, path, (struct resource *) ts); + + return ts; } static void XMLCALL -xml_mapelem_end(void *data, const char *el) +tmx_map_start(void *pv, const char *name, const char **attr) { - struct tmx *tmx; + XML_Parser p = (XML_Parser) pv; + struct map *m; - debug(" (type \"mapelem\")", el); + debug("<%s> (map)", name); - tmx = (struct tmx *) data; - - if (xml_check_tag(el, "tileset")) { - XML_SetStartElementHandler(tmx->p, xml_mapelem_start); - XML_SetEndElementHandler(tmx->p, xml_map_end); - } else if (xml_check_tag(el, "layer")) { - XML_SetStartElementHandler(tmx->p, xml_mapelem_start); - XML_SetEndElementHandler(tmx->p, xml_map_end); - } else if (xml_check_tag(el, "objectgroup")) { - XML_SetStartElementHandler(tmx->p, xml_mapelem_start); - XML_SetEndElementHandler(tmx->p, xml_map_end); + if (xml_check_tag(name, "map")) { + m = resource_alloc("", sizeof(*m)); + if (m == NULL) { + XML_StopParser(p, XML_FALSE); + return; + } + xml_get_int_attr(p, attr, "width", &m->width, 1); + xml_get_int_attr(p, attr, "height", &m->height, 1); + xml_get_int_attr(p, attr, "tilewidth", &m->tilewidth, 1); + xml_get_int_attr(p, attr, "tileheight", &m->tileheight, 1); + debug("pushing node"); + xml_node_push(p, m, tmx_map_el_start, tmx_map_end, NULL); } else { - xml_unexpected_end_tag(tmx->p, el, - "tileset, layer, or objectgroup"); + xml_unexpected_start_tag(p, name, "map"); } } static void XMLCALL -xml_image_start(void *data, const char *el, const char **attr) +tmx_map_end(void *pv, const char *name) { - struct tmx *tmx; - struct tileset *ts; - char *source; - - debug("<%s> (type \"image\")", el); + XML_Parser p = (XML_Parser) pv; + struct map *m; - tmx = (struct tmx *) data; + debug(" (map)", name); - if (xml_check_tag(el, "image")) { - ts = tmx->map->tilesets_tail; - xml_get_string_attr(tmx->p, attr, "source", - &source, 1); - ts->image = img_png_get(source); - free(source); - XML_SetStartElementHandler(tmx->p, NULL); - XML_SetEndElementHandler(tmx->p, xml_image_end); + if (xml_check_tag(name, "map")) { + /* A hack to expose the map back to map_get(). */ + m = xml_node_pop(p); + xml_node_push(p, m, tmx_invalid_start, tmx_invalid_end, NULL); } else { - xml_unexpected_end_tag(tmx->p, el, - "image"); + xml_unexpected_end_tag(p, name, "map"); } } static void XMLCALL -xml_image_end(void *data, const char *el) +tmx_map_el_start(void *pv, const char *name, const char **attr) { - struct tmx *tmx; - - tmx = (struct tmx *) data; + XML_Parser p = (XML_Parser) pv; + char *source; + struct tileset *ts; - debug(" (type \"image\")", el); + debug("<%s> (map child)", name); - if (xml_check_tag(el, "image")) { - XML_SetStartElementHandler(tmx->p, NULL); - XML_SetEndElementHandler(tmx->p, xml_mapelem_end); + if (xml_check_tag(name, "properties")) { + /* Not used by engine. */ + xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL); + } else if (xml_check_tag(name, "tileset")) { + source = NULL; + xml_get_string_attr(p, attr, "source", &source, 0); + if (source != NULL) { + /* External tilesheet. */ + ts = tileset_get(source); + free(source); + xml_node_push(p, ts, tmx_invalid_start, tmx_ext_ts_end, + NULL); + } else { + /* Pass through. */ + tmx_tileset_start(pv, name, attr); + ts = (struct tileset *) xml_node_peek(p); + } + xml_get_int_attr(p, attr, "firstgid", &ts->firstgid, 1); + xml_get_string_attr(p, attr, "name", &ts->name, 1); } else { - xml_unexpected_end_tag(tmx->p, el, - "image"); + xml_unexpected_start_tag(p, name, + "properties, tileset, layer, or objectgroup"); } } static void XMLCALL -xml_data_start(void *data, const char *el, const char **attr) +tmx_tileset_start(void *pv, const char *name, const char **attr) { - struct tmx *tmx; - struct layer *ly; - - debug("<%s> (type \"data\")", el); - - tmx = (struct tmx *) data; - - if (xml_check_tag(el, "data")) { - ly = tmx->map->layers_tail; - xml_get_string_attr(tmx->p, attr, "encoding", - &ly->encoding, 0); - xml_get_string_attr(tmx->p, attr, "compression", - &ly->compression, 0); - XML_SetStartElementHandler(tmx->p, NULL); - XML_SetEndElementHandler(tmx->p, xml_data_end); - XML_SetCharacterDataHandler(tmx->p, xml_data_data); + XML_Parser p = (XML_Parser) pv; + struct tileset *ts; + + debug("<%s> (tileset)", name); + + if (xml_check_tag(name, "tileset")) { + ts = resource_alloc("", sizeof(*ts)); + xml_get_string_attr(p, attr, "name", &ts->name, 1); + xml_get_int_attr(p, attr, "tilewidth", &ts->tilewidth, 1); + xml_get_int_attr(p, attr, "tileheight", &ts->tileheight, 1); + xml_node_push(p, ts, tmx_tileset_el_start, tmx_tileset_end, + NULL); } else { - xml_unexpected_start_tag(tmx->p, el, - "data"); + xml_unexpected_start_tag(p, name, "tileset"); } } static void XMLCALL -xml_data_data(void *data, const char *s, int len) +tmx_tileset_end(void *pv, const char *name) { - struct tmx *tmx; - char *s_z; - char *s_z_trimmed, *s_z_trimmed_end; - - debug("...LAYER DATA..."); - - tmx = (struct tmx *) data; + XML_Parser p = (XML_Parser) pv; + struct tileset *ts; - s_z = s_z_trimmed = strndup(s, len); + debug(" (tileset)", name); - while(isspace(*s_z_trimmed)) { - ++s_z_trimmed; - --len; - } - if (*s_z_trimmed == '\0') { - return; - } - s_z_trimmed_end = s_z_trimmed + len - 1; - while (s_z_trimmed_end > s_z_trimmed && isspace(*s_z_trimmed_end)) { - --s_z_trimmed_end; + if (xml_check_tag(name, "tileset")) { + ts = (struct tileset *) xml_node_pop(p); + /* XXX?? */ + resource_use((struct resource *) ts); + resource_add(&ts_res, "", (struct resource *) ts); + } else { + xml_unexpected_end_tag(p, name, "tileset"); } - *(s_z_trimmed_end + 1) = '\0'; - - tmx->layer_data = strdup(s_z_trimmed); - - free(s_z); } static void XMLCALL -xml_data_end(void *data, const char *el) +tmx_ext_ts_end(void *pv, const char *name) { - struct tmx *tmx; - - debug(" (type \"data\")", el); + XML_Parser p = (XML_Parser) pv; + struct tileset *ts; - tmx = (struct tmx *) data; + debug(" (tileset link)", name); - if (xml_check_tag(el, "data")) { - XML_SetStartElementHandler(tmx->p, NULL); - XML_SetEndElementHandler(tmx->p, xml_mapelem_end); - XML_SetCharacterDataHandler(tmx->p, NULL); + if (xml_check_tag(name, "tileset")) { + ts = (struct tileset *) xml_node_pop(p); + map_add_tileset((struct map *) xml_node_peek(p), ts); } else { - xml_unexpected_end_tag(tmx->p, el, - "data"); + xml_unexpected_end_tag(p, name, "tileset"); } } static void XMLCALL -xml_object_start(void *data, const char *el, - const char **attr) +tmx_tileset_el_start(void *pv, const char *name, const char **attr) { - struct tmx *tmx; - char *type; - - debug("<%s> (type \"object\")", el); + XML_Parser p = (XML_Parser) pv; + char *source; + struct image *img; - tmx = (struct tmx *) data; + debug("<%s> (tileset child)", name); - if (xml_check_tag(el, "object")) { - /* TODO: Handle objects. */ - xml_get_string_attr(tmx->p, attr, "type", - &type, 1); - if (strcmp(type, "exit") == 0) { - } else if (strcmp(type, "exit") == 0) { - } - XML_SetStartElementHandler(tmx->p, NULL); - XML_SetEndElementHandler(tmx->p, xml_object_end); + if (xml_check_tag(name, "image")) { + xml_get_string_attr(p, attr, "source", &source, 0); + img = NULL; /*img_png_get(source);*/ + free(source); + xml_node_push(p, img, tmx_invalid_start, tmx_image_end, NULL); } else { - xml_unexpected_start_tag(tmx->p, el, - "object"); + xml_unexpected_start_tag(p, name, "image"); } } static void XMLCALL -xml_object_end(void *data, const char *el) +tmx_image_end(void *pv, const char *name) { - struct tmx *tmx; - - debug(" (type \"object\")", el); + XML_Parser p = (XML_Parser) pv; + struct image *img; + struct tileset *ts; - tmx = (struct tmx *) data; + debug(" (image)", name); - if (xml_check_tag(el, "object")) { - XML_SetStartElementHandler(tmx->p, xml_object_start); - XML_SetEndElementHandler(tmx->p, xml_mapelem_end); + if (xml_check_tag(name, "image")) { + img = (struct image *) xml_node_pop(p); + ts = (struct tileset *) xml_node_peek(p); + ts->image = img; } else { - xml_unexpected_end_tag(tmx->p, el, - "object"); + xml_unexpected_end_tag(p, name, "image"); } } -struct map * -map_get(const char *path) +static void XMLCALL +tmx_unused_start(void *pv, const char *name, const char **attr) { - struct tmx tmx; - FILE *tmx_fp; - void *tmx_buf; - size_t len; - enum XML_Status status; - - memset(&tmx, 0, sizeof(tmx)); + XML_Parser p = (XML_Parser) pv; - tmx.map = (struct map *) resource_get(&map_res, path); - if (tmx.map != NULL) { - resource_use((struct resource *) tmx.map); - return tmx.map; - } + debug("<%s> (unused)", name); - tmx.map = resource_alloc(path, sizeof(*tmx.map)); + /* Shut up, GCC. */ + for (; *name != '\0'; ++name); + for (; *attr != NULL; ++attr); - tmx.p = XML_ParserCreate(NULL); - if (tmx.p == NULL) { - warn("Failed to create TMX parser"); - return NULL; - } + xml_node_push(p, NULL, tmx_unused_start, tmx_unused_end, NULL); +} - XML_SetStartElementHandler(tmx.p, xml_map_start); - XML_SetEndElementHandler(tmx.p, NULL); - XML_SetCharacterDataHandler(tmx.p, NULL); +static void XMLCALL +tmx_unused_end(void *pv, const char *name) +{ + XML_Parser p = (XML_Parser) pv; - XML_SetUserData(tmx.p, &tmx); + debug("<%s> (unused)", name); - tmx_fp = fopen(path, "rb"); - if (tmx_fp == NULL) { - warn("Failed to open TMX file"); - XML_ParserFree(tmx.p); - return NULL; - } + /* Shut up, GCC. */ + for (; *name != '\0'; ++name); - tmx_buf = XML_GetBuffer(tmx.p, 8192); - if (tmx_buf == NULL) { - warn("Failed to create TMX parse buffer"); - XML_ParserFree(tmx.p); - fclose(tmx_fp); - return NULL; - } + xml_node_pop(p); +} - while (!feof(tmx_fp)) { - len = fread(tmx_buf, 1, 8192, tmx_fp); - status = XML_ParseBuffer(tmx.p, len, feof(tmx_fp)); - if (status == XML_STATUS_OK) { - continue; - } - warn("Failed to parse TMX file (%s)", - XML_ErrorString(XML_GetErrorCode(tmx.p))); - XML_ParserFree(tmx.p); - fclose(tmx_fp); - return NULL; - } +static void XMLCALL +tmx_invalid_start(void *pv, const char *name, const char **attr) +{ + XML_Parser p = (XML_Parser) pv; - XML_ParserFree(tmx.p); - fclose(tmx_fp); + debug("<%s> (invalid)", name); - resource_use((struct resource *) tmx.map); - resource_add(&map_res, path, (struct resource *) tmx.map); + /* Shut up, GCC. */ + for (; *attr != NULL; ++attr); - return tmx.map; + xml_unexpected_start_tag(p, name, ""); } -void -map_add_layer(struct map *m, struct layer *l) +static void XMLCALL +tmx_invalid_end(void *pv, const char *name) { - if (m->layers_head == NULL) { - m->layers_head = l; - } else { - m->layers_tail->next = l; - } - m->layers_tail = l; -} + XML_Parser p = (XML_Parser) pv; -void -map_add_tileset(struct map *m, struct tileset *t) -{ - if (m->tilesets_head == NULL) { - m->tilesets_head = t; - } else { - m->tilesets_tail->next = t; - } - m->tilesets_tail = t; + debug("<%s> (invalid)", name); + + xml_unexpected_end_tag(p, name, ""); } -- cgit v0.9.1