1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 /* TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all
24 */
25 
26 #ifdef __WINRT__
27 
28 extern "C" {
29 #include "SDL_filesystem.h"
30 #include "SDL_error.h"
31 #include "SDL_hints.h"
32 #include "SDL_stdinc.h"
33 #include "SDL_system.h"
34 #include "../../core/windows/SDL_windows.h"
35 }
36 
37 #include <string>
38 #include <unordered_map>
39 
40 using namespace std;
41 using namespace Windows::Storage;
42 
43 extern "C" const wchar_t *
SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType)44 SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType)
45 {
46     switch (pathType) {
47         case SDL_WINRT_PATH_INSTALLED_LOCATION:
48         {
49             static wstring path;
50             if (path.empty()) {
51                 path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
52             }
53             return path.c_str();
54         }
55 
56         case SDL_WINRT_PATH_LOCAL_FOLDER:
57         {
58             static wstring path;
59             if (path.empty()) {
60                 path = ApplicationData::Current->LocalFolder->Path->Data();
61             }
62             return path.c_str();
63         }
64 
65 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
66         case SDL_WINRT_PATH_ROAMING_FOLDER:
67         {
68             static wstring path;
69             if (path.empty()) {
70                 path = ApplicationData::Current->RoamingFolder->Path->Data();
71             }
72             return path.c_str();
73         }
74 
75         case SDL_WINRT_PATH_TEMP_FOLDER:
76         {
77             static wstring path;
78             if (path.empty()) {
79                 path = ApplicationData::Current->TemporaryFolder->Path->Data();
80             }
81             return path.c_str();
82         }
83 #endif
84 
85         default:
86             break;
87     }
88 
89     SDL_Unsupported();
90     return NULL;
91 }
92 
93 extern "C" const char *
SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType)94 SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType)
95 {
96     typedef unordered_map<SDL_WinRT_Path, string> UTF8PathMap;
97     static UTF8PathMap utf8Paths;
98 
99     UTF8PathMap::iterator searchResult = utf8Paths.find(pathType);
100     if (searchResult != utf8Paths.end()) {
101         return searchResult->second.c_str();
102     }
103 
104     const wchar_t * ucs2Path = SDL_WinRTGetFSPathUNICODE(pathType);
105     if (!ucs2Path) {
106         return NULL;
107     }
108 
109     char * utf8Path = WIN_StringToUTF8(ucs2Path);
110     utf8Paths[pathType] = utf8Path;
111     SDL_free(utf8Path);
112     return utf8Paths[pathType].c_str();
113 }
114 
115 extern "C" char *
SDL_GetBasePath(void)116 SDL_GetBasePath(void)
117 {
118     const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_INSTALLED_LOCATION);
119     size_t destPathLen;
120     char * destPath = NULL;
121 
122     if (!srcPath) {
123         SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError());
124         return NULL;
125     }
126 
127     destPathLen = SDL_strlen(srcPath) + 2;
128     destPath = (char *) SDL_malloc(destPathLen);
129     if (!destPath) {
130         SDL_OutOfMemory();
131         return NULL;
132     }
133 
134     SDL_snprintf(destPath, destPathLen, "%s\\", srcPath);
135     return destPath;
136 }
137 
138 extern "C" char *
SDL_GetPrefPath(const char * org,const char * app)139 SDL_GetPrefPath(const char *org, const char *app)
140 {
141     /* WinRT note: The 'SHGetFolderPath' API that is used in Windows 7 and
142      * earlier is not available on WinRT or Windows Phone.  WinRT provides
143      * a similar API, but SHGetFolderPath can't be called, at least not
144      * without violating Microsoft's app-store requirements.
145      */
146 
147     const WCHAR * srcPath = NULL;
148     WCHAR path[MAX_PATH];
149     char *retval = NULL;
150     WCHAR* worg = NULL;
151     WCHAR* wapp = NULL;
152     size_t new_wpath_len = 0;
153     BOOL api_result = FALSE;
154 
155     if (!app) {
156         SDL_InvalidParamError("app");
157         return NULL;
158     }
159     if (!org) {
160         org = "";
161     }
162 
163     srcPath = SDL_WinRTGetFSPathUNICODE(SDL_WINRT_PATH_LOCAL_FOLDER);
164     if ( ! srcPath) {
165         SDL_SetError("Unable to find a source path");
166         return NULL;
167     }
168 
169     if (SDL_wcslen(srcPath) >= MAX_PATH) {
170         SDL_SetError("Path too long.");
171         return NULL;
172     }
173     SDL_wcslcpy(path, srcPath, SDL_arraysize(path));
174 
175     worg = WIN_UTF8ToString(org);
176     if (worg == NULL) {
177         SDL_OutOfMemory();
178         return NULL;
179     }
180 
181     wapp = WIN_UTF8ToString(app);
182     if (wapp == NULL) {
183         SDL_free(worg);
184         SDL_OutOfMemory();
185         return NULL;
186     }
187 
188     new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3;
189 
190     if ((new_wpath_len + 1) > MAX_PATH) {
191         SDL_free(worg);
192         SDL_free(wapp);
193         SDL_SetError("Path too long.");
194         return NULL;
195     }
196 
197     if (*worg) {
198         SDL_wcslcat(path, L"\\", new_wpath_len + 1);
199         SDL_wcslcat(path, worg, new_wpath_len + 1);
200         SDL_free(worg);
201     }
202 
203     api_result = CreateDirectoryW(path, NULL);
204     if (api_result == FALSE) {
205         if (GetLastError() != ERROR_ALREADY_EXISTS) {
206             SDL_free(wapp);
207             WIN_SetError("Couldn't create a prefpath.");
208             return NULL;
209         }
210     }
211 
212     SDL_wcslcat(path, L"\\", new_wpath_len + 1);
213     SDL_wcslcat(path, wapp, new_wpath_len + 1);
214     SDL_free(wapp);
215 
216     api_result = CreateDirectoryW(path, NULL);
217     if (api_result == FALSE) {
218         if (GetLastError() != ERROR_ALREADY_EXISTS) {
219             WIN_SetError("Couldn't create a prefpath.");
220             return NULL;
221         }
222     }
223 
224     SDL_wcslcat(path, L"\\", new_wpath_len + 1);
225 
226     retval = WIN_StringToUTF8(path);
227 
228     return retval;
229 }
230 
231 #endif /* __WINRT__ */
232 
233 /* vi: set ts=4 sw=4 expandtab: */
234