]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Rewritten ini support, no more 64k section size limits.
authorToni Wilen <twilen@winuae.net>
Sun, 2 Jul 2017 07:48:36 +0000 (10:48 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 2 Jul 2017 07:48:36 +0000 (10:48 +0300)
od-win32/registry.cpp

index 498dc6e814e5f0e4fb39baefd3d322c41c20de54..93f1d1dfdaa746dc43438a16c385532faf172275 100644 (file)
 
 static int inimode = 0;
 static TCHAR *inipath;
-#define PUPPA _T("eitätäoo")
+
+#define ROOT_TREE _T("WinUAE")
+
+static struct ini_line **inidata;
+static int inilines;
+
+struct ini_line
+{
+       int section_order;
+       TCHAR *section;
+       TCHAR *key;
+       TCHAR *value;
+};
+
+static TCHAR *initrim(TCHAR *s)
+{
+       while (*s != 0 && *s <= 32)
+               s++;
+       TCHAR *s2 = s;
+       while (*s2)
+               s2++;
+       while (s2 > s) {
+               s2--;
+               if (*s2 > 32)
+                       break;
+               *s2 = 0;
+       }
+       return s;
+}
+
+static void ini_free(void)
+{
+       for(int c = 0; c < inilines; c++) {
+               struct ini_line *il = inidata[c];
+               xfree(il->section);
+               xfree(il->key);
+               xfree(il->value);
+               xfree(il);
+               inidata[c] = NULL;
+       }
+}
+
+static void ini_sort(void)
+{
+       for(int c1 = 0; c1 < inilines; c1++) {
+               struct ini_line *il1 = inidata[c1];
+               if (il1 == NULL)
+                       continue;
+               for (int c2 = c1 + 1; c2 < inilines; c2++) {
+                       struct ini_line *il2 = inidata[c2];
+                       if (il2 == NULL)
+                               continue;
+                       int order = 0;
+                       int sec = _tcsicmp(il1->section, il2->section);
+                       if (sec) {
+                               if (!il1->section_order && !il2->section_order)
+                                       order = sec;
+                               else
+                                       order = il2->section_order - il1->section_order;
+                       } else {
+                               order = _tcsicmp(il1->key, il2->key);
+                       }
+                       if (order > 0) {
+                               struct ini_line il;
+                               memcpy(&il, il1, sizeof(struct ini_line));
+                               memcpy(il1, il2, sizeof(struct ini_line));
+                               memcpy(il2, &il, sizeof(struct ini_line));
+                       }
+               }
+       }
+#if 0
+       for(int c1 = 0; c1 < inilines; c1++) {
+               struct ini_line *il1 = inidata[c1];
+               if (il1)
+                       write_log(_T("[%s] %s %s\n"), il1->section, il1->key, il1->value);
+       }
+       write_log(_T("\n"));
+#endif
+}
+
+static void ini_addnewstring(const TCHAR *section, const TCHAR *key, const TCHAR *val)
+{
+       struct ini_line *il = xcalloc(struct ini_line, 1);
+       il->section = my_strdup(section);
+       if (!_tcsicmp(section, ROOT_TREE))
+               il->section_order = 1;
+       il->key = my_strdup(key);
+       il->value = my_strdup(val);
+       int cnt = 0;
+       while (cnt < inilines && inidata[cnt])
+               cnt++;
+       if (cnt == inilines) {
+               inilines += 10;
+               inidata = xrealloc(struct ini_line*, inidata, inilines);
+               int cnt2 = cnt;
+               while (cnt2 < inilines) {
+                       inidata[cnt2++] = NULL;
+               }
+       }
+       inidata[cnt] = il;
+}
+
+static const uae_u8 bom[3] = { 0xef, 0xbb, 0xbf };
+
+static void ini_load(const TCHAR *path)
+{
+       bool utf8 = false;
+       TCHAR section[MAX_DPATH];
+       uae_u8 tmp[3];
+
+       ini_free();
+
+       FILE *f = _tfopen(path, _T("rb"));
+       if (!f)
+               return;
+       int v = fread(tmp, 1, sizeof tmp, f);
+       fclose (f);
+       if (v == 3 && tmp[0] == 0xef && tmp[1] == 0xbb && tmp[2] == 0xbf) {
+               f = _tfopen (path, _T("rt, ccs=UTF-8"));
+       } else {
+               f = _tfopen (path, _T("rt"));
+       }
+       section[0] = 0;
+       for (;;) {
+               TCHAR tbuffer[MAX_DPATH];
+               tbuffer[0] = 0;
+               if (!fgetws(tbuffer, MAX_DPATH, f))
+                       break;
+               TCHAR *s = initrim(tbuffer);
+               if (_tcslen(s) < 3)
+                       continue;
+               if (s[0] == '[' && s[_tcslen(s) - 1] == ']') {
+                       s[_tcslen(s) - 1] = 0;
+                       _tcscpy(section, s + 1);
+                       continue;
+               }
+               if (section[0] == 0)
+                       continue;
+               TCHAR *s1 = _tcschr(s, '=');
+               if (s1) {
+                       *s1++ = 0;
+                       TCHAR *s2 = initrim(tbuffer);
+                       TCHAR *s3 = initrim(s1);
+                       ini_addnewstring(section, s2, s3);
+               }
+       }
+       fclose(f);
+       ini_sort();
+}
+
+static void ini_save(const TCHAR *path)
+{
+       TCHAR section[MAX_DPATH];
+       TCHAR sep[2] = { '=', 0 };
+       TCHAR lf[2] = {  10, 0 };
+       TCHAR left[2] = { '[', 0 };
+       TCHAR right[2] = { ']', 0 };
+
+       ini_sort();
+       FILE *f = _tfopen(path, _T("wt, ccs=UTF-8"));
+       if (!f)
+               return;
+       section[0] = 0;
+       for (int c = 0; c < inilines; c++) {
+               TCHAR out[MAX_DPATH];
+               struct ini_line *il = inidata[c];
+               if (!il)
+                       continue;
+               if (_tcscmp(il->section, section)) {
+                       _tcscpy(out, lf);
+                       _tcscat(out, left);
+                       _tcscat(out, il->section);
+                       _tcscat(out, right);
+                       _tcscat(out, lf);
+                       fputws(out, f);
+                       _tcscpy(section, il->section);
+               }
+               _tcscpy(out, il->key);
+               _tcscat(out, sep);
+               _tcscat(out, il->value);
+               _tcscat(out, lf);
+               fputws(out, f);
+       }
+       fclose(f);
+}
+
+static bool ini_getstring(const TCHAR *section, const TCHAR *key, TCHAR *out, int *max)
+{
+       for (int c = 0; c < inilines; c++) {
+               struct ini_line *il = inidata[c];
+               if (il && !_tcscmp(section, il->section) && (key == NULL || !_tcscmp(key, il->key))) {
+                       if (out) {
+                               _tcsncpy(out, il->value, *max);
+                               out[*max - 1] = 0;
+                               *max = _tcslen(out);
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
+
+static bool ini_getsectionstring(const TCHAR *section, int idx, TCHAR *keyout, int *keysize, TCHAR *valout, int *valsize)
+{
+       for (int c = 0; c < inilines; c++) {
+               struct ini_line *il = inidata[c];
+               if (il && !_tcscmp(section, il->section)) {
+                       if (idx == 0) {
+                               if (keyout) {
+                                       _tcsncpy(keyout, il->key, *keysize);
+                                       keyout[*keysize - 1] = 0;
+                                       *keysize = _tcslen(keyout);
+                               }
+                               if (valout) {
+                                       _tcsncpy(valout, il->value, *valsize);
+                                       valout[*valsize - 1] = 0;
+                                       *valsize = _tcslen(valout);
+                               }
+                               return true;
+                       }
+                       idx--;
+               }
+       }
+       return false;
+}
+
+static bool ini_addstring(const TCHAR *section, const TCHAR *key, const TCHAR *val)
+{
+       for (int c = 0; c < inilines; c++) {
+               struct ini_line *il = inidata[c];
+               if (il && !_tcscmp(section, il->section)) {
+                       if (!_tcscmp(key, il->key)) {
+                               xfree(il->value);
+                               il->value = my_strdup(val);
+                               return true;
+                       }
+               }
+       }
+       ini_addnewstring(section, key, val);
+       return true;
+}
+
+static void ini_delete(const TCHAR *section, const TCHAR *key)
+{
+       for (int c = 0; c < inilines; c++) {
+               struct ini_line *il = inidata[c];
+               if (il && !_tcscmp(section, il->section) && (key == NULL || !_tcscmp(key, il->key))) {
+                       xfree(il->section);
+                       xfree(il->key);
+                       xfree(il->value);
+                       xfree(il);
+                       inidata[c] = NULL;
+               }
+       }
+}
+
 
 static HKEY gr (UAEREG *root)
 {
@@ -21,7 +276,7 @@ static HKEY gr (UAEREG *root)
 static TCHAR *gs (UAEREG *root)
 {
        if (!root)
-               return _T("WinUAE");
+               return ROOT_TREE;
        return root->inipath;
 }
 static TCHAR *gsn (UAEREG *root, const TCHAR *name)
@@ -38,8 +293,7 @@ static TCHAR *gsn (UAEREG *root, const TCHAR *name)
 int regsetstr (UAEREG *root, const TCHAR *name, const TCHAR *str)
 {
        if (inimode) {
-               DWORD ret;
-               ret = WritePrivateProfileString (gs (root), name, str, inipath);
+               int ret = ini_addstring(gs(root), name, str);
                return ret;
        } else {
                HKEY rk = gr (root);
@@ -52,10 +306,10 @@ int regsetstr (UAEREG *root, const TCHAR *name, const TCHAR *str)
 int regsetint (UAEREG *root, const TCHAR *name, int val)
 {
        if (inimode) {
-               DWORD ret;
+               int ret;
                TCHAR tmp[100];
                _stprintf (tmp, _T("%d"), val);
-               ret = WritePrivateProfileString (gs (root), name, tmp, inipath);
+               ret = ini_addstring(gs(root), name, tmp);
                return ret;
        } else {
                DWORD v = val;
@@ -71,8 +325,8 @@ int regqueryint (UAEREG *root, const TCHAR *name, int *val)
        if (inimode) {
                int ret = 0;
                TCHAR tmp[100];
-               GetPrivateProfileString (gs (root), name, PUPPA, tmp, sizeof (tmp) / sizeof (TCHAR), inipath);
-               if (_tcscmp (tmp, PUPPA)) {
+               int size = sizeof tmp / sizeof(TCHAR);
+               if (ini_getstring(gs(root), name, tmp, &size)) {
                        *val = _tstol (tmp);
                        ret = 1;
                }
@@ -90,10 +344,10 @@ int regqueryint (UAEREG *root, const TCHAR *name, int *val)
 int regsetlonglong (UAEREG *root, const TCHAR *name, ULONGLONG val)
 {
        if (inimode) {
-               DWORD ret;
+               int ret;
                TCHAR tmp[100];
                _stprintf (tmp, _T("%I64d"), val);
-               ret = WritePrivateProfileString (gs (root), name, tmp, inipath);
+               ret = ini_addstring(gs(root), name, tmp);
                return ret;
        } else {
                ULONGLONG v = val;
@@ -110,8 +364,8 @@ int regquerylonglong (UAEREG *root, const TCHAR *name, ULONGLONG *val)
        if (inimode) {
                int ret = 0;
                TCHAR tmp[100];
-               GetPrivateProfileString (gs (root), name, PUPPA, tmp, sizeof (tmp) / sizeof (TCHAR), inipath);
-               if (_tcscmp (tmp, PUPPA)) {
+               int size = sizeof tmp / sizeof(TCHAR);
+               if (ini_getstring(gs(root), name, tmp, &size)) {
                        *val = _tstoi64 (tmp);
                        ret = 1;
                }
@@ -131,8 +385,7 @@ int regquerystr (UAEREG *root, const TCHAR *name, TCHAR *str, int *size)
        if (inimode) {
                int ret = 0;
                TCHAR *tmp = xmalloc (TCHAR, (*size) + 1);
-               GetPrivateProfileString (gs (root), name, PUPPA, tmp, *size, inipath);
-               if (_tcscmp (tmp, PUPPA)) {
+               if (ini_getstring(gs(root), name, tmp, size)) {
                        _tcscpy (str, tmp);
                        ret = 1;
                }
@@ -154,28 +407,7 @@ int regenumstr (UAEREG *root, int idx, TCHAR *name, int *nsize, TCHAR *str, int
        name[0] = 0;
        str[0] = 0;
        if (inimode) {
-               int ret = 0;
-               int tmpsize = 65536;
-               TCHAR *tmp = xmalloc (TCHAR, tmpsize);
-               if (GetPrivateProfileSection (gs (root), tmp, tmpsize, inipath) > 0) {
-                       int i;
-                       TCHAR *p = tmp, *p2;
-                       for (i = 0; i < idx; i++) {
-                               if (p[0] == 0)
-                                       break;
-                               p += _tcslen (p) + 1;
-                       }
-                       if (p[0]) {
-                               p2 = _tcschr (p, '=');
-                               if (p2) {
-                                       *p2++ = 0;
-                                       _tcscpy_s (name, *nsize, p);
-                                       _tcscpy_s (str, *size, p2);
-                                       ret = 1;
-                               }
-                       }
-               }
-               xfree (tmp);
+               int ret = ini_getsectionstring(gs(root), idx, name, nsize, str, size);
                return ret;
        } else {
                DWORD nsize2 = *nsize;
@@ -217,12 +449,11 @@ int regsetdata (UAEREG *root, const TCHAR *name, const void *str, int size)
 {
        if (inimode) {
                uae_u8 *in = (uae_u8*)str;
-               DWORD ret;
-               int i;
+               int ret;
                TCHAR *tmp = xmalloc (TCHAR, size * 2 + 1);
-               for (i = 0; i < size; i++)
+               for (int i = 0; i < size; i++)
                        _stprintf (tmp + i * 2, _T("%02X"), in[i]); 
-               ret = WritePrivateProfileString (gs (root), name, tmp, inipath);
+               ret = ini_addstring(gs(root), name, tmp);
                xfree (tmp);
                return ret;
        } else {
@@ -279,7 +510,7 @@ err:
 int regdelete (UAEREG *root, const TCHAR *name)
 {
        if (inimode) {
-               WritePrivateProfileString (gs (root), name, NULL, inipath);
+               ini_delete(gs(root), name);
                return 1;
        } else {
                HKEY rk = gr (root);
@@ -292,13 +523,9 @@ int regdelete (UAEREG *root, const TCHAR *name)
 int regexists (UAEREG *root, const TCHAR *name)
 {
        if (inimode) {
-               int ret = 1;
-               TCHAR *tmp = xmalloc (TCHAR, _tcslen (PUPPA) + 1);
-               int size = _tcslen (PUPPA) + 1;
-               GetPrivateProfileString (gs (root), name, PUPPA, tmp, size, inipath);
-               if (!_tcscmp (tmp, PUPPA))
-                       ret = 0;
-               xfree (tmp);
+               if (!inilines)
+                       return 0;
+               int ret = ini_getstring(gs(root), name, NULL, NULL);
                return ret;
        } else {
                HKEY rk = gr (root);
@@ -314,7 +541,7 @@ void regdeletetree (UAEREG *root, const TCHAR *name)
                TCHAR *s = gsn (root, name);
                if (!s)
                        return;
-               WritePrivateProfileSection (s, _T(""), inipath);
+               ini_delete(s, NULL);
                xfree (s);
        } else {
                HKEY rk = gr (root);
@@ -328,23 +555,10 @@ int regexiststree (UAEREG *root, const TCHAR *name)
 {
        if (inimode) {
                int ret = 0;
-               int tmpsize = 65536;
-               TCHAR *p, *tmp;
                TCHAR *s = gsn (root, name);
                if (!s)
                        return 0;
-               tmp = xmalloc (TCHAR, tmpsize / sizeof (TCHAR));
-               tmp[0] = 0;
-               GetPrivateProfileSectionNames (tmp, tmpsize, inipath);
-               p = tmp;
-               while (p[0]) {
-                       if (!_tcscmp (p, name)) {
-                               ret = 1;
-                               break;
-                       }
-                       p += _tcslen (p) + 1;
-               }
-               xfree (tmp);
+               ret = ini_getstring(s, NULL, NULL, 0);
                xfree (s);
                return ret;
        } else {
@@ -402,6 +616,8 @@ void regclosetree (UAEREG *key)
 {
        if (!key)
                return;
+       if (inimode)
+               ini_save(inipath);
        if (key->fkey)
                RegCloseKey (key->fkey);
        xfree (key->inipath);
@@ -446,6 +662,7 @@ int reginitializeinit (TCHAR **pppath)
 
        inimode = 1;
        inipath = my_strdup (fpath);
+       ini_load(inipath);
        if (!regexists (NULL, _T("Version")))
                goto fail;
        return 1;