textures, lightmaps, hardcoded texture hack for testing
[laserbrain_demo] / src / datamap.cc
index bf8854c..626c47f 100644 (file)
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <vector>
 #include <map>
 #include <string>
+#include <regex>
 #include "datamap.h"
 
-static std::vector<std::pair<std::string, std::string>> dmap;
+#ifdef WIN32
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+
+static char *clean_line(char *s);
+
+static std::vector<std::pair<std::regex, std::string>> dmap;
 static std::map<std::string, std::string> cache;
 static std::string root;
 
-void datmap_reset()
+void datamap_reset()
 {
        root.clear();
        dmap.clear();
        cache.clear();
 }
 
-void datmap_set_path(const char *path)
+void datamap_set_path(const char *path)
 {
        root = std::string(path);
 }
 
-bool datmap_load_map(const char *fname)
+bool datamap_load_map(const char *fname)
 {
        std::string path = root.empty() ? fname : root + std::string("/") + fname;
-       return false;   // TODO cont...
+       fname = path.c_str();
+
+       FILE *fp = fopen(fname, "r");
+       if(!fp) {
+               fprintf(stderr, "failed to open data map: %s\n", fname);
+               return false;
+       }
+
+       char buf[256];
+       if(fread(buf, 1, 8, fp) < 8 || memcmp(buf, "DATAMAP0", 8) != 0) {
+               fprintf(stderr, "invalid datamap file: %s\n", fname);
+               fclose(fp);
+               return false;
+       }
+
+       datamap_reset();
+
+       char *line;
+       int nline = 0;
+       while(fgets(buf, sizeof buf, fp)) {
+               ++nline;
+               line = clean_line(buf);
+               if(!line || !*line) continue;
+
+               char *colon = strchr(line, ':');
+               if(!colon) {
+                       goto err;
+               }
+               *colon = 0;
+
+               std::pair<std::regex, std::string> pair;
+               pair.first = std::regex(line);
+
+               char *value = clean_line(colon + 1);
+               if(!value || !*value) {
+                       goto err;
+               }
+               pair.second = std::string(value);
+               dmap.push_back(pair);
+       }
+       fclose(fp);
+
+       printf("loaded datamap %s: %d mappings\n", fname, (int)dmap.size());
+       return true;
+
+err:
+       fprintf(stderr, "error while parsing %s, invalid line %d: %s\n", fname, nline, line);
+       datamap_reset();
+       fclose(fp);
+       return false;
 }
 
-void datmap_map(const char *re, const char *path)
+void datamap_map(const char *re, const char *path)
 {
-       std::pair<std::string, std::string> mapping;
-       mapping.first = std::string(re);
+       std::pair<std::regex, std::string> mapping;
+       mapping.first = std::regex(re);
        mapping.second = std::string(path);
-       dmap.push_back(mapping);
+       dmap.push_back(std::move(mapping));
+}
+
+int datamap_lookup(const char *in, char *buf, int bsz)
+{
+       std::string res;
+
+       char *inbuf = (char*)alloca(strlen(in) + 1);
+       strcpy(inbuf, in);
+       in = clean_line(inbuf);
+
+       // first check the cache
+       std::map<std::string, std::string>::iterator it = cache.find(in);
+       if(it != cache.end()) {
+               res = it->second;
+       } else {
+               // try matching with the available mappings
+               int num = dmap.size();
+               for(int i=0; i<num; i++) {
+                       if(std::regex_match(in, dmap[i].first)) {
+                               res = root.empty() ? dmap[i].second : root + "/" + dmap[i].second;
+                               cache[in] = res;        // add it to the cache
+                               break;
+                       }
+               }
+               return 0;
+       }
+
+       // copy result in buf, truncating if necessary and return the size of the
+       // buffer required to hold it
+       if(buf) {
+               int n = std::min(bsz - 1, (int)res.length());
+               memcpy(buf, res.c_str(), n);
+               buf[bsz - 1] = 0; // make sure it's null-terminated even if it got truncated
+       }
+       return res.length() + 1;
 }
 
-int datmap_lookup(const char *in, char *buf, int bsz)
+int datamap_path_size(const char *in)
 {
-       return -1;      // TODO
+       return datamap_lookup(in, 0, 0);
 }
 
-int datmap_path_size(const char *in)
+static char *clean_line(char *s)
 {
-       return datmap_lookup(in, 0, 0);
+       while(*s && isspace(*s)) ++s;
+       if(!*s) return 0;
+
+       char *end;
+       if(!(end = strchr(s, '#'))) {
+               end = s + strlen(s) - 1;
+       }
+       while(end > s && isspace(*end)) --end;
+       if(s == end) return 0;
+       end[1] = 0;
+
+       // app-specific: convert backslashes
+       char *c = s;
+       while(*c) {
+               if(*c == '\\') *c = '/';
+               ++c;
+       }
+
+       return s;
 }