src/filesystem/winrt/SDL_sysfilesystem.cpp
changeset 9247 eddb899239fe
parent 9242 f4d353bd5d16
child 9255 c2ef0d8d6da0
--- a/src/filesystem/winrt/SDL_sysfilesystem.cpp	Fri Nov 28 04:51:33 2014 -0800
+++ b/src/filesystem/winrt/SDL_sysfilesystem.cpp	Sat Nov 29 10:09:30 2014 -0500
@@ -144,49 +144,121 @@
      * without violating Microsoft's app-store requirements.
      */
 
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
-    /* A 'Roaming' folder is not available in Windows Phone 8.0, however a
-     * 'Local' folder is.  Use the 'Local' folder in order to preserve
-     * compatibility with Windows Phone 8.0, and with app-installs that have
-     * been updated from 8.0-based, to 8.1-based apps.
+    /* Default to using a Local/non-Roaming path.  WinRT will often attempt
+     * to synchronize files in Roaming paths, and will do so while an app is
+     * running.  Using a Local path prevents the possibility that an app's
+     * save-data files will get changed from underneath it, without it
+     * being ready.
+     *
+     * This behavior can be changed via use of the
+     * SDL_HINT_WINRT_PREF_PATH_ROOT hint.
      */
     SDL_WinRT_Path pathType = SDL_WINRT_PATH_LOCAL_FOLDER;
-#else
-    /* A 'Roaming' folder is available on Windows 8 and 8.1.  Use that.
-     */
-    SDL_WinRT_Path pathType = SDL_WINRT_PATH_ROAMING_FOLDER;
-#endif
 
     const char * hint = SDL_GetHint(SDL_HINT_WINRT_PREF_PATH_ROOT);
     if (hint) {
         if (SDL_strcasecmp(hint, "local") == 0) {
             pathType = SDL_WINRT_PATH_LOCAL_FOLDER;
-        }
+        } else if (SDL_strcasecmp(hint, "roaming") == 0) {
 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
-        else if (SDL_strcasecmp(hint, "roaming") == 0) {
             pathType = SDL_WINRT_PATH_ROAMING_FOLDER;
+#else
+            /* Don't apply a 'Roaming' path on Windows Phone 8.0.  Roaming
+             * data is not supported by that version of the operating system.
+             */
+            SDL_SetError("A Roaming path was specified via SDL_HINT_WINRT_PREF_PATH_ROOT, but Roaming is not supported on Windows Phone 8.0");
+            return NULL;
+#endif
+        } else if (SDL_strcasecmp(hint, "old") == 0) {
+            /* Older versions of SDL/WinRT, including 2.0.3, would return a
+             * pref-path that used a Roaming folder on non-Phone versions of
+             * Windows, such as Windows 8.0 and Windows 8.1.  This has since
+             * been reverted to using a Local folder, in order to prevent
+             * problems arising from WinRT automatically synchronizing files
+             * during an app's lifetime.  In case this functionality is
+             * desired, setting SDL_HINT_WINRT_PREF_PATH_ROOT to "old" will
+             * trigger the older behavior.
+             */
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+            pathType = SDL_WINRT_PATH_LOCAL_FOLDER;
+#else
+            pathType = SDL_WINRT_PATH_ROAMING_FOLDER;
+#endif
         }
-#endif
     }
 
-    const char * srcPath = SDL_WinRTGetFSPathUTF8(pathType);
-    size_t destPathLen;
-    char * destPath = NULL;
+    const WCHAR * srcPath = NULL;
+    WCHAR path[MAX_PATH];
+    char *retval = NULL;
+    WCHAR* worg = NULL;
+    WCHAR* wapp = NULL;
+    size_t new_wpath_len = 0;
+    BOOL api_result = FALSE;
 
-    if (!srcPath) {
-        SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError());
+    srcPath = SDL_WinRTGetFSPathUNICODE(pathType);
+    if ( ! srcPath) {
+        SDL_SetError("Unable to find a source path");
         return NULL;
     }
 
-    destPathLen = SDL_strlen(srcPath) + SDL_strlen(org) + SDL_strlen(app) + 4;
-    destPath = (char *) SDL_malloc(destPathLen);
-    if (!destPath) {
+    if (SDL_wcslen(srcPath) >= MAX_PATH) {
+        SDL_SetError("Path too long.");
+        return NULL;
+    }
+    SDL_wcslcpy(path, srcPath, SDL_arraysize(path));
+
+    worg = WIN_UTF8ToString(org);
+    if (worg == NULL) {
         SDL_OutOfMemory();
         return NULL;
     }
 
-    SDL_snprintf(destPath, destPathLen, "%s\\%s\\%s\\", srcPath, org, app);
-    return destPath;
+    wapp = WIN_UTF8ToString(app);
+    if (wapp == NULL) {
+        SDL_free(worg);
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3;
+
+    if ((new_wpath_len + 1) > MAX_PATH) {
+        SDL_free(worg);
+        SDL_free(wapp);
+        SDL_SetError("Path too long.");
+        return NULL;
+    }
+
+    SDL_wcslcat(path, L"\\", new_wpath_len + 1);
+    SDL_wcslcat(path, worg, new_wpath_len + 1);
+    SDL_free(worg);
+
+    api_result = CreateDirectoryW(path, NULL);
+    if (api_result == FALSE) {
+        if (GetLastError() != ERROR_ALREADY_EXISTS) {
+            SDL_free(wapp);
+            WIN_SetError("Couldn't create a prefpath.");
+            return NULL;
+        }
+    }
+
+    SDL_wcslcat(path, L"\\", new_wpath_len + 1);
+    SDL_wcslcat(path, wapp, new_wpath_len + 1);
+    SDL_free(wapp);
+
+    api_result = CreateDirectoryW(path, NULL);
+    if (api_result == FALSE) {
+        if (GetLastError() != ERROR_ALREADY_EXISTS) {
+            WIN_SetError("Couldn't create a prefpath.");
+            return NULL;
+        }
+    }
+
+    SDL_wcslcat(path, L"\\", new_wpath_len + 1);
+
+    retval = WIN_StringToUTF8(path);
+
+    return retval;
 }
 
 #endif /* __WINRT__ */