diff --git a/flips-gtk.cpp b/flips-gtk.cpp index 222ac69..d38401f 100644 --- a/flips-gtk.cpp +++ b/flips-gtk.cpp @@ -845,6 +845,10 @@ int GUIShow(const char * filename) int main(int argc, char * argv[]) { canShowGUI=gtk_parse_args(&argc, &argv); + if (canShowGUI) + { + cfg.load_file(get_cfgpath()); + } return flipsmain(argc, argv); } #endif diff --git a/flips.cpp b/flips.cpp index c3c28d0..6c3038f 100644 --- a/flips.cpp +++ b/flips.cpp @@ -76,7 +76,8 @@ struct mem file::read() { struct mem out; out.len = len(); - out.ptr = (uint8_t*)malloc(out.len); + out.ptr = (uint8_t*)malloc(out.len + sizeof(WCHAR)); + memset(out.ptr + out.len, 0, sizeof(WCHAR)); if (!read(out.ptr, 0, out.len)) { free(out.ptr); @@ -180,34 +181,146 @@ enum patchtype IdentifyPatch(file* patch) - -config::config(struct mem contents) +//this is the most inefficient possible implementation. it works, that's all I care about +void config::init_raw(LPWSTR contents) { + LPCWSTR header = TEXT("[Flips]\n"); + + if (wcsncmp(contents, header, wcslen(header)) != 0) return; + contents += wcslen(header); + + //I need to somehow ensure that stepping backwards across whitespace doesn't go before the original string. + //This can be done with while (iswspace(*contents)) contents++;, but demanding the header above works just as well. + + while (true) + { + LPWSTR key; + LPWSTR keyend; + LPWSTR val; + LPWSTR valend; + + LPWSTR nextline = wcschr(contents, '\n'); + + if (nextline != NULL) valend = nextline; + else valend = wcschr(contents, '\0'); + //do not move inside the conditional, it screws up the strchr + while (iswspace(valend[-1])) valend--; + *valend = '\0'; + + LPWSTR sep = wcschr(contents, '='); + if (sep != NULL) + { + key = contents; + keyend = sep; + val = sep+1; + + while (iswspace(key[0])) key++; + while (iswspace(keyend[-1])) keyend--; + *keyend = '\0'; + while (iswspace(val[0])) val++; + + if (valend>val && keyend>key) + { + set(key, val); + } + } + + if (!nextline) break; + contents = nextline+1; + while (contents && iswspace(*contents)) contents++; + } } -config::config(LPCWSTR filename) +void config::init_file(LPCWSTR filename) { + struct mem data = file::read(filename); + if (data.len > 0 && data.len%sizeof(WCHAR) == 0) + { + this->init_raw((LPWSTR)(data.ptr)); + } + free(data.ptr); + + this->filename = wcsdup(filename); } -void config::setbin(const char * name, struct mem value) +void config::set(LPCWSTR name, LPCWSTR value) { +//printf("(%s)(%s)\n",name,value); + for (size_t i=0;inumentries;i++) + { + if (!wcscmp(name, this->names[i])) + { + free(this->values[i]); + this->values[i] = wcsdup(value); + return; + } + } + + this->numentries++; + this->names = (LPWSTR*)realloc(this->names, sizeof(LPWSTR)*this->numentries); + this->values = (LPWSTR*)realloc(this->values, sizeof(LPWSTR)*this->numentries); + + this->names[this->numentries-1] = wcsdup(name); + this->values[this->numentries-1] = wcsdup(value); } -struct mem config::getbin(const char * name) +LPCWSTR config::get(LPCWSTR name) { + for (size_t i=0;inumentries;i++) + { + if (!wcscmp(name, this->names[i])) + { + return this->values[i]; + } + } + return NULL; } -struct mem config::flatten() +LPWSTR config::flatten() { + LPCWSTR header = TEXT("[Flips]\n"); + + size_t len = wcslen(header); + for (size_t i=0;inumentries;i++) + { + len += wcslen(this->names[i]) + 1 + wcslen(this->values[i]) + 1; + } + + LPWSTR ret = (LPWSTR)malloc((len+1)*sizeof(WCHAR)); + + LPWSTR at = ret; + at += wsprintf(at, "%s", header); + for (size_t i=0;inumentries;i++) + { + at += wsprintf(at, "%s=%s\n", this->names[i], this->values[i]); + } + + return ret; } config::~config() { - if (this->filename) filewrite::write(this->filename, this->contents); - free(this->filename); - free(this->contents.ptr); + if (this->filename) + { + LPWSTR data = this->flatten(); +//puts(data); + filewrite::write(this->filename, (struct mem){ (uint8_t*)data, wcslen(data)*sizeof(WCHAR) }); + free(data); + free(this->filename); + } + + for (size_t i=0;inumentries;i++) + { +//printf("#(%s)(%s)\n",this->names[i],this->values[i]); + free(this->names[i]); + free(this->values[i]); + } + free(this->names); + free(this->values); } +config cfg; + diff --git a/flips.h b/flips.h index 59c9572..54fb7b3 100644 --- a/flips.h +++ b/flips.h @@ -34,7 +34,7 @@ //#define EXTERN_C //#endif -#define flipsversion "Flips v1.32" +#define flipsversion "Flips v1.40" #if defined(FLIPS_WINDOWS) @@ -53,6 +53,7 @@ #include #include #include +#include #define wcsicmp _wcsicmp//wcsicmp deprecated? fuck that, I use what I want. I do not add underlines to a few randomly chosen functions. #define wcsdup _wcsdup @@ -65,15 +66,17 @@ #include #include #include +#include //Flips uses Windows type names internally, since it's easier to #define them to Linux types than -//defining "const char *" to anything else, and since I use char* at some places (mainly libips/etc) -//and really don't want to try to split them. Inventing my own typedefs seems counterproductive as +//defining "const char *" to anything else. Inventing my own typedefs seems counterproductive as //well; they would bring no advantage over Windows typenames except not being Windows typenames, and //I don't see that as a valid argument. + #define LPCWSTR const char * #define LPWSTR char * #define WCHAR char + #define wcscpy strcpy #define wcscat strcat #define wcschr strchr @@ -85,15 +88,32 @@ #define wcsicmp strcasecmp //#define wcsnicmp strncasecmp #define wprintf printf +#define wsprintf sprintf + +#define iswalnum isalnum +#define iswalpha isalpha +#define iswascii isascii +#define iswblank isblank +#define iswcntrl iscntrl +#define iswdigit isdigit +#define iswgraph isgraph +#define iswlower islower +#define iswprint isprint +#define iswpunct ispunct +#define iswspace isspace +#define iswupper isupper +#define iswxdigit isxdigit + #define TEXT(text) text //EXTERN_C int strcasecmp(const char *s1, const char *s2); +//some platforms define strdup, some don't. #define strdup strdup_flips static inline char* strdup(const char * in) { size_t len=strlen(in); char * ret=(char*)malloc(len+1); - strcpy(ret, in); + memcpy(ret, in, len+1); return ret; } #endif @@ -157,29 +177,43 @@ bool shouldRemoveHeader(LPCWSTR romname, size_t romlen); class config { LPWSTR filename; - struct mem contents; + + size_t numentries; + LPWSTR * names; + LPWSTR * values; + + //stupid c++, why is there no sane way to get the implementation out of the headers + bool parse(LPCWSTR contents); public: - config(struct mem contents); - config(LPCWSTR filename); - void set(const char * name, LPCWSTR value) + config() { - setbin(name, (struct mem){(uint8_t*)value, (wcslen(value)+1)*sizeof(WCHAR)}); + numentries = 0; + names = NULL; + values = NULL; } - void setbin(const char * name, struct mem value); - // free() these three when you're done with them. - LPWSTR get(const char * name) - { - return (LPWSTR)(getbin(name).ptr); - } - struct mem getbin(const char * name); + //This ends up writing a really ugly format on Windows: UTF-16, no BOM, LF endings. + // I can't do anything else without adding a #ifdef, and that would reward Microsoft for being + // dickbutts and not supporting UTF-8 properly. + //I could use CRLF instead, but I want the file broken in Notepad; if I use CRLF, it adds a BOM, + // and there's no way to get rid of that without a ifdef. If I break the file, people won't try. + //If the input is invalid, the object will ignore the invalid parts and remain valid. + //In particular, failing to initialize from a file will update the file on destruction. + //Only init once. + void init_file(LPCWSTR filename); + void init_raw(LPWSTR contents); // Modifies the contents. - struct mem flatten(); + //Neither of those may have leading or trailing whitespace, or contain a \n. \r isn't recommended either. + //Additionally, the name may not contain =. + void set(LPCWSTR name, LPCWSTR value); + LPCWSTR get(LPCWSTR name); - ~config(); + LPWSTR flatten(); // free() this when you're done. + ~config(); // If you used init_file, this saves automatically. }; +extern config cfg; struct mem GetRomList(); void SetRomList(struct mem data); diff --git a/global.h b/global.h index 5b041b8..20d548a 100644 --- a/global.h +++ b/global.h @@ -33,6 +33,7 @@ public: virtual size_t len() = 0; virtual bool read(uint8_t* target, size_t start, size_t len) = 0; + //these two add sizeof(WCHAR) 00s after the actual data, so you can cast it to LPCWSTR (assuming it's aligned) static struct mem read(LPCWSTR filename); // provided by Flips core struct mem read(); // provided by Flips core