From 661af077b2d956aaf840c98b05303ac95f12c6dd Mon Sep 17 00:00:00 2001
From: Sara <sara@saragerretsen.nl>
Date: Fri, 22 Sep 2023 17:12:00 +0200
Subject: [PATCH] refactored tilemap_load to use tiled xml format

---
 src/tilemap.c | 111 ++++++++++++++++++++++++++++++++++----------------
 src/tilemap.h |   2 +-
 2 files changed, 77 insertions(+), 36 deletions(-)

diff --git a/src/tilemap.c b/src/tilemap.c
index 1d0dd99..58d7595 100644
--- a/src/tilemap.c
+++ b/src/tilemap.c
@@ -1,54 +1,95 @@
 #include "tilemap.h"
+#include "libxml/threads.h"
+#include "libxml/tree.h"
+#include "libxml/xmlstring.h"
 #include "program.h"
 #include <SDL2/SDL_image.h>
+#include <libxml/xinclude.h>
 #include <stdio.h>
 
-struct Tilemap tilemap_load(const char* tilemap_file, const char* tileset_file) {
+#define XML(__str) (const xmlChar*)__str
+
+static inline
+void tilemap_get_size_from_xml(xmlNodePtr node, int* o_width, int* o_height) {
+    xmlChar* prop = xmlGetProp(node, XML("width"));
+    if(prop == NULL) { printf("Nu-uh\n"); return; }
+    *o_width = atoi((char*)prop);
+
+    prop = xmlGetProp(node, XML("height"));
+    if(prop == NULL) { printf("Nu-uh\n"); return; }
+    *o_height = atoi((char*)prop);
+}
+
+static inline
+void tilemap_get_tiles_from_xml(xmlDoc* doc, xmlNodePtr node, int* out, int out_len) {
+    node = node->children;
+    while(xmlStrcmp(node->name, XML("data")) != 0 && node != NULL) {
+        node = node->next;
+    }
+
+    if(node == NULL) {
+        memset(out, 0x0, out_len * sizeof(int));
+        return;
+    }
+
+    char buffer[5]; buffer[4] = '\0';
+    char* buffer_writer = buffer;
+    int* out_writer = out;
+    xmlChar* str = xmlNodeGetContent(node);
+    xmlChar* reader = str;
+
+    while(*reader != '\0') {
+       while(isspace(*reader)) 
+            reader++;
+        if(*reader != ',' && *reader != '\0') {
+            *buffer_writer = (char)*reader;
+            ++buffer_writer;
+        } else {
+            *buffer_writer = '\0';
+            buffer_writer = buffer;
+            *out_writer = atoi(buffer) - 1;
+            ++out_writer;
+        }
+        ++reader;
+    }
+}
+
+struct Tilemap tilemap_load(const char* tilemap_file) {
     struct Tilemap self = {
         .dimensions = {1,1},
         .tiles = NULL
     };
 
-    FILE* fs = fopen(tilemap_file, "r");
-    int n = 0;
-    do {
-        n = fgetc(fs);
-        if(n == ',') {
-            self.dimensions.x++;
-        }
-    } while(n != '\n');
-    do {
-        n = fgetc(fs);
-        if(n == '\n') {
-            self.dimensions.y++;
-        }
-    } while(n != '\0');
+    xmlDocPtr doc = xmlParseFile(tilemap_file);
+    if(doc == NULL) {
+        printf("Failed to load tilemap file '%s'\n", tilemap_file);
+        self.dimensions.x = self.dimensions.y = 0;
+        return self;
+    }
 
-    rewind(fs);
+    xmlNodePtr reader = xmlDocGetRootElement(doc);
+    if(reader == NULL) {
+        printf("Failed to find map node in tilemap '%s'\n", tilemap_file);
+        self.dimensions.x = self.dimensions.y = 0;
+        xmlFreeDoc(doc);
+        return self;
+    }
 
-    self.tiles = malloc(self.dimensions.x * self.dimensions.y * sizeof(int));
-
-    char csv_buffer[6];
-    csv_buffer[5] = '\0';
-    char* writer = csv_buffer;
-    int* tile = self.tiles;
+    reader = reader->children;
 
     do {
-        n = fgetc(fs);
-        if(isalnum(n)) {
-            *writer = n;
-            ++writer;
-        } else if(n == ',' || n == '\0' || n == '\n') {
-            *writer = '\0';
-            writer = csv_buffer;
-            *tile = atoi(csv_buffer);
-            ++tile;
+        if(xmlStrcmp(reader->name, XML("layer")) == 0) {
+            tilemap_get_size_from_xml(reader, &self.dimensions.x, &self.dimensions.y);
+            printf("sizes: %d %d\n", self.dimensions.x, self.dimensions.y);
+            self.tiles = malloc(self.dimensions.x * self.dimensions.y * sizeof(int));
+            printf("reading layer data\n");
+            tilemap_get_tiles_from_xml(doc, reader, self.tiles, self.dimensions.x * self.dimensions.y);
+        } else if(xmlStrcmp(reader->name, XML("objectgroup"))) {
         }
-    } while(n != '\0');
+        reader = reader->next;
+    } while(reader != NULL);
 
-    fclose(fs);
-
-    self.tileset = tileset_load(tileset_file);
+    xmlFreeDoc(doc);
     
     return self;
 }
diff --git a/src/tilemap.h b/src/tilemap.h
index 3427d87..6cc11a5 100644
--- a/src/tilemap.h
+++ b/src/tilemap.h
@@ -18,7 +18,7 @@ struct Tilemap {
 	struct Tileset tileset;
 };
 
-extern struct Tilemap tilemap_load(const char* tilemap_file, const char* tileset_file);
+extern struct Tilemap tilemap_load(const char* tilemap_file);
 extern struct Tileset tileset_load(const char* filename);
 extern SDL_Rect tileset_index_to_rect(struct Tileset* self, size_t index);