/* * Copyright (C) 2021 P. J. McDermott * * This file is part of Dodge Balls * * Dodge Balls 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 3 of the License, or * (at your option) any later version. * * Dodge Balls 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 Dodge Balls. If not, see . */ #include #include #include #include #include "dirs.h" #include "map.h" #include "output.h" #include "xml.h" struct db_map { }; static char * _db_map_path(const char *game_id, const char *file, const char *ext) { const char *games_dir; char *path; games_dir = db_get_games_dir(); path = malloc((strlen(games_dir) + strlen(game_id) + strlen(file) + strlen(ext) + 3) * sizeof(*path)); if (path == NULL) { db_err("Failed to allocate memory"); return NULL; } sprintf(path, "%s/%s/%s%s", games_dir, game_id, file, ext); return path; } static void XMLCALL _db_tmx_invalid_end(void *pv, const char *name) { XML_Parser p; db_dbg(" (invalid)", name); p = (XML_Parser) pv; db_xml_unexpected_end_tag(p, name, ""); } static void XMLCALL _db_tmx_invalid_start(void *pv, const char *name, const char **attr __attribute__((__unused__))) { XML_Parser p; db_dbg(" <%s> (invalid)", name); p = (XML_Parser) pv; db_xml_node_push(p, NULL, _db_tmx_invalid_start, _db_tmx_invalid_end, NULL); } static void XMLCALL _db_tmx_map_end(void *pv, const char *name) { XML_Parser p; db_dbg(" (map)", name); p = (XML_Parser) pv; if (db_xml_check_tag(name, "map")) { db_xml_node_pop(p); } else { db_xml_unexpected_end_tag(p, name, "map"); } } static void XMLCALL _db_tmx_map_start(void *pv, const char *name, const char **attr __attribute__((__unused__))) { XML_Parser p; struct db_map *map; db_dbg(" <%s> (map)", name); p = (XML_Parser) pv; map = db_xml_node_peek(p); if (db_xml_check_tag(name, "map")) { db_xml_node_push(p, map, _db_tmx_invalid_start, _db_tmx_map_end, NULL); } else { db_xml_unexpected_start_tag(p, name, "map"); } } struct db_map * db_map_new(const char *game_id, const char *level_id) { struct db_map *map; XML_Parser p; char *path; FILE *fp; void *buf; size_t len; enum XML_Status status; map = calloc(1, sizeof(*map)); if (map == NULL) { db_err("Failed to allocate memory"); return NULL; } p = XML_ParserCreate(NULL); if (p == NULL) { free(map); return NULL; } XML_UseParserAsHandlerArg(p); db_xml_node_push(p, map, _db_tmx_map_start, _db_tmx_invalid_end, NULL); path = _db_map_path(game_id, level_id, ".tmx"); if (path == NULL) { db_xml_node_pop(p); XML_ParserFree(p); free(path); free(map); return NULL; } fp = fopen(path, "rb"); if (fp == NULL) { db_xml_node_pop(p); XML_ParserFree(p); free(path); free(map); return NULL; } buf = XML_GetBuffer(p, 8192); if (buf == NULL) { db_xml_node_pop(p); XML_ParserFree(p); free(path); fclose(fp); free(map); return NULL; } db_dbg("Parsing <%s>:", path); free(path); while (!feof(fp)) { len = fread(buf, 1, 8192, fp); status = XML_ParseBuffer(p, len, feof(fp)); if (status == XML_STATUS_OK) { continue; } db_err("Failed to parse map information (%s)", XML_ErrorString(XML_GetErrorCode(p))); db_xml_node_pop(p); XML_ParserFree(p); fclose(fp); free(map); return NULL; } db_dbg("Parsing done"); db_xml_node_pop(p); XML_ParserFree(p); fclose(fp); return map; }