diff --git a/esm/Makefile b/esm/Makefile index 4d7d4098d..9b51817ea 100644 --- a/esm/Makefile +++ b/esm/Makefile @@ -1 +1,3 @@ all: reader + +reader: reader.cpp ../tools/stringops.cpp diff --git a/esm/reader.cpp b/esm/reader.cpp index e35a8daa6..e75998659 100644 --- a/esm/reader.cpp +++ b/esm/reader.cpp @@ -9,6 +9,8 @@ using namespace std; #include "../mangle/stream/servers/file_stream.h" #include "../mangle/tools/str_exception.h" +#include "../tools/stringops.h" + /* A structure used for holding fixed-length strings. In the case of LEN=4, it can be more efficient to match the string as a 32 bit number, therefore the struct is implemented as a union with an int. @@ -87,6 +89,7 @@ class ESMReader HEDRstruct header; SaveData saveData; + int spf; // Special file signifier (see SpecialFile below) public: enum Version @@ -102,6 +105,17 @@ public: FT_ESS = 32 // Savegame }; + // Used to mark special files. The original ESM files are given + // special treatment in a few places, most noticably in loading and + // filtering out "dirtly" GMST entries correctly. + enum SpecialFile + { + SF_Other, + SF_Morrowind, + SF_Tribunal, + SF_Bloodmoon + }; + void open(Mangle::Stream::StreamPtr _esm, const string &name) { esm = _esm; @@ -113,7 +127,13 @@ public: recName.val = 0; subName.val = 0; - // TODO: determine special file status from file name + // Flag certain files for special treatment, based on the file + // name. + const char *cstr = filename.c_str(); + if(iends(cstr, "Morrowind.esm")) spf = SF_Morrowind; + else if(iends(cstr, "Tribunal.esm")) spf = SF_Tribunal; + else if(iends(cstr, "Bloodmoon.esm")) spf = SF_Bloodmoon; + else spf = SF_Other; if(getRecName() != "TES3") fail("Not a valid Morrowind file"); diff --git a/tools/stringops.cpp b/tools/stringops.cpp index a74027179..fcb1aff27 100644 --- a/tools/stringops.cpp +++ b/tools/stringops.cpp @@ -1,6 +1,7 @@ #include "stringops.h" #include +#include bool begins(const char* str1, const char* str2) { @@ -23,3 +24,36 @@ bool ends(const char* str1, const char* str2) return strcmp(str2, str1+len1-len2) == 0; } + +// True if the given chars match, case insensitive +static bool icmp(char a, char b) +{ + if(a >= 'A' && a <= 'Z') + a += 'a' - 'A'; + if(b >= 'A' && b <= 'Z') + b += 'a' - 'A'; + + return a == b; +} + +bool ibegins(const char* str1, const char* str2) +{ + while(*str2) + { + if(*str1 == 0 || !icmp(*str1,*str2)) return false; + + str1++; + str2++; + } + return true; +} + +bool iends(const char* str1, const char* str2) +{ + int len1 = strlen(str1); + int len2 = strlen(str2); + + if(len1 < len2) return false; + + return strcasecmp(str2, str1+len1-len2) == 0; +} diff --git a/tools/stringops.h b/tools/stringops.h index 30c6c1f10..e76b8a87a 100644 --- a/tools/stringops.h +++ b/tools/stringops.h @@ -7,4 +7,10 @@ bool begins(const char* str1, const char* str2); /// Returns true if str1 ends with substring str2 bool ends(const char* str1, const char* str2); +/// Case insensitive, returns true if str1 begins with substring str2 +bool ibegins(const char* str1, const char* str2); + +/// Case insensitive, returns true if str1 ends with substring str2 +bool iends(const char* str1, const char* str2); + #endif diff --git a/tools/tests/strops_test.cpp b/tools/tests/strops_test.cpp index 8991f5623..6c4b3e802 100644 --- a/tools/tests/strops_test.cpp +++ b/tools/tests/strops_test.cpp @@ -14,5 +14,35 @@ int main() assert(!begins("abc", "bcd")); assert(!begins("abc", "abcd")); + assert(ibegins("Abc", "a")); + assert(ibegins("aBc", "ab")); + assert(ibegins("abC", "abc")); + assert(ibegins("abcD", "abc")); + + assert(!ibegins("abc", "b")); + assert(!ibegins("abc", "bc")); + assert(!ibegins("abc", "bcd")); + assert(!ibegins("abc", "abcd")); + + assert(ends("abc", "c")); + assert(ends("abc", "bc")); + assert(ends("abc", "abc")); + assert(ends("abcd", "abcd")); + + assert(!ends("abc", "b")); + assert(!ends("abc", "ab")); + assert(!ends("abc", "bcd")); + assert(!ends("abc", "abcd")); + + assert(iends("Abc", "c")); + assert(iends("aBc", "bc")); + assert(iends("abC", "abc")); + assert(iends("abcD", "abcd")); + + assert(!iends("abc", "b")); + assert(!iends("abc", "ab")); + assert(!iends("abc", "bcd")); + assert(!iends("abc", "abcd")); + return 0; }