1 #include "FileSystemUtils.h"
2
3 #include <vector>
4 #include <string>
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include <SDL.h>
11 #include <physfs.h>
12
13 #if defined(_WIN32)
14 #include <windows.h>
15 #include <shlobj.h>
16 #define mkdir(a, b) CreateDirectory(a, NULL)
17 #define VNEEDS_MIGRATION (mkdirResult != 0)
18 #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
19 #include <sys/stat.h>
20 #include <limits.h>
21 #define VNEEDS_MIGRATION (mkdirResult == 0)
22 /* These are needed for PLATFORM_* crap */
23 #include <unistd.h>
24 #include <dirent.h>
25 #define MAX_PATH PATH_MAX
26 #endif
27
28 char saveDir[MAX_PATH];
29 char levelDir[MAX_PATH];
30
31 void PLATFORM_getOSDirectory(char* output);
32 void PLATFORM_migrateSaveData(char* output);
33 void PLATFORM_copyFile(const char *oldLocation, const char *newLocation);
34
FILESYSTEM_init(char * argvZero)35 int FILESYSTEM_init(char *argvZero)
36 {
37 char output[MAX_PATH];
38 int mkdirResult;
39
40 PHYSFS_init(argvZero);
41
42 /* Determine the OS user directory */
43 PLATFORM_getOSDirectory(output);
44
45 /* Create base user directory, mount */
46 mkdirResult = mkdir(output, 0777);
47
48 /* Mount our base user directory */
49 PHYSFS_mount(output, NULL, 1);
50 printf("Base directory: %s\n", output);
51
52 /* Create save directory */
53 strcpy(saveDir, output);
54 strcat(saveDir, "saves");
55 strcat(saveDir, PHYSFS_getDirSeparator());
56 mkdir(saveDir, 0777);
57 printf("Save directory: %s\n", saveDir);
58
59 /* Create level directory */
60 strcpy(levelDir, output);
61 strcat(levelDir, "levels");
62 strcat(levelDir, PHYSFS_getDirSeparator());
63 mkdirResult |= mkdir(levelDir, 0777);
64 printf("Level directory: %s\n", levelDir);
65
66 /* We didn't exist until now, migrate files! */
67 if (VNEEDS_MIGRATION)
68 {
69 PLATFORM_migrateSaveData(output);
70 }
71
72 /* Mount the stock content last */
73 #ifdef _WIN32
74 strcpy(output, PHYSFS_getBaseDir());
75 strcat(output, "data.zip");
76 #elif defined(__FreeBSD__)
77 PLATFORM_getOSDirectory(output);
78 if (strlcat(output, "data.zip", sizeof(output)) >= sizeof(output)) {
79 puts("Cannot find location for data.zip\n");
80 return 0;
81 }
82 #else
83 strcpy(output, "data.zip");
84 #endif
85 if (!PHYSFS_mount(output, NULL, 1))
86 {
87 puts("Error: data.zip missing!");
88 puts("You do not have data.zip!");
89 puts("Grab it from your purchased copy of the game,");
90 puts("or get it from the free Make and Play Edition.");
91
92 SDL_ShowSimpleMessageBox(
93 SDL_MESSAGEBOX_ERROR,
94 "data.zip missing!",
95 "You do not have data.zip!"
96 "\n\nGrab it from your purchased copy of the game,"
97 "\nor get it from the free Make and Play Edition.",
98 NULL
99 );
100 return 0;
101 }
102 return 1;
103 }
104
FILESYSTEM_deinit()105 void FILESYSTEM_deinit()
106 {
107 PHYSFS_deinit();
108 }
109
FILESYSTEM_getUserSaveDirectory()110 char *FILESYSTEM_getUserSaveDirectory()
111 {
112 return saveDir;
113 }
114
FILESYSTEM_getUserLevelDirectory()115 char *FILESYSTEM_getUserLevelDirectory()
116 {
117 return levelDir;
118 }
119
FILESYSTEM_loadFileToMemory(const char * name,unsigned char ** mem,size_t * len)120 void FILESYSTEM_loadFileToMemory(const char *name, unsigned char **mem, size_t *len)
121 {
122 PHYSFS_File *handle = PHYSFS_openRead(name);
123 if (handle == NULL)
124 {
125 return;
126 }
127 PHYSFS_uint32 length = PHYSFS_fileLength(handle);
128 if (len != NULL)
129 {
130 *len = length;
131 }
132 *mem = (unsigned char*) malloc(length);
133 PHYSFS_read(handle, *mem, 1, length);
134 PHYSFS_close(handle);
135 }
136
FILESYSTEM_freeMemory(unsigned char ** mem)137 void FILESYSTEM_freeMemory(unsigned char **mem)
138 {
139 free(*mem);
140 *mem = NULL;
141 }
142
FILESYSTEM_getLevelDirFileNames()143 std::vector<std::string> FILESYSTEM_getLevelDirFileNames()
144 {
145 std::vector<std::string> list;
146 char **fileList = PHYSFS_enumerateFiles("/levels");
147 char **i;
148 std::string builtLocation;
149
150 for (i = fileList; *i != NULL; i++)
151 {
152 if (strcmp(*i, "data") == 0)
153 {
154 continue; /* FIXME: lolwut -flibit */
155 }
156 builtLocation = "levels/";
157 builtLocation += *i;
158 list.push_back(builtLocation);
159 }
160
161 PHYSFS_freeList(fileList);
162
163 return list;
164 }
165
PLATFORM_getOSDirectory(char * output)166 void PLATFORM_getOSDirectory(char* output)
167 {
168 #if defined(__linux__) || defined(__FreeBSD__)
169 const char *homeDir = getenv("XDG_DATA_HOME");
170 if (homeDir == NULL)
171 {
172 strcpy(output, PHYSFS_getUserDir());
173 strcat(output, ".local/share/VVVVVV/");
174 }
175 else
176 {
177 strcpy(output, homeDir);
178 strcat(output, "/VVVVVV/");
179 }
180 #elif defined(__APPLE__)
181 strcpy(output, PHYSFS_getUserDir());
182 strcat(output, "Library/Application Support/VVVVVV/");
183 #elif defined(_WIN32)
184 SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, output);
185 strcat(output, "\\VVVVVV\\");
186 #else
187 #error See PLATFORM_getOSDirectory
188 #endif
189 }
190
PLATFORM_migrateSaveData(char * output)191 void PLATFORM_migrateSaveData(char* output)
192 {
193 char oldLocation[MAX_PATH];
194 char newLocation[MAX_PATH];
195 char oldDirectory[MAX_PATH];
196 #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
197 DIR *dir = NULL;
198 struct dirent *de = NULL;
199 DIR *subDir = NULL;
200 struct dirent *subDe = NULL;
201 char subDirLocation[MAX_PATH];
202 const char *homeDir = getenv("HOME");
203 if (homeDir == NULL)
204 {
205 /* Uhh, I don't want to get near this. -flibit */
206 return;
207 }
208 strcpy(oldDirectory, homeDir);
209 #if defined(__linux__) || defined(__FreeBSD__)
210 strcat(oldDirectory, "/.vvvvvv/");
211 #elif defined(__APPLE__)
212 strcat(oldDirectory, "/Documents/VVVVVV/");
213 #endif
214 dir = opendir(oldDirectory);
215 if (!dir)
216 {
217 printf("Could not find directory %s\n", oldDirectory);
218 return;
219 }
220
221 printf("Migrating old savedata to new location...\n");
222 for (de = readdir(dir); de != NULL; de = readdir(dir))
223 {
224 if ( strcmp(de->d_name, "..") == 0 ||
225 strcmp(de->d_name, ".") == 0 )
226 {
227 continue;
228 }
229 #define COPY_SAVEFILE(name) \
230 else if (strcmp(de->d_name, name) == 0) \
231 { \
232 strcpy(oldLocation, oldDirectory); \
233 strcat(oldLocation, name); \
234 strcpy(newLocation, output); \
235 strcat(newLocation, "saves/"); \
236 strcat(newLocation, name); \
237 PLATFORM_copyFile(oldLocation, newLocation); \
238 }
239 COPY_SAVEFILE("unlock.vvv")
240 COPY_SAVEFILE("tsave.vvv")
241 COPY_SAVEFILE("qsave.vvv")
242 #undef COPY_SAVEFILE
243 else if (strstr(de->d_name, ".vvvvvv.vvv") != NULL)
244 {
245 strcpy(oldLocation, oldDirectory);
246 strcat(oldLocation, de->d_name);
247 strcpy(newLocation, output);
248 strcat(newLocation, "saves/");
249 strcat(newLocation, de->d_name);
250 PLATFORM_copyFile(oldLocation, newLocation);
251 }
252 else if (strstr(de->d_name, ".vvvvvv") != NULL)
253 {
254 strcpy(oldLocation, oldDirectory);
255 strcat(oldLocation, de->d_name);
256 strcpy(newLocation, output);
257 strcat(newLocation, "levels/");
258 strcat(newLocation, de->d_name);
259 PLATFORM_copyFile(oldLocation, newLocation);
260 }
261 else if (strcmp(de->d_name, "Saves") == 0)
262 {
263 strcpy(subDirLocation, oldDirectory);
264 strcat(subDirLocation, "Saves/");
265 subDir = opendir(subDirLocation);
266 if (!subDir)
267 {
268 printf("Could not open Saves/ subdir!\n");
269 continue;
270 }
271 for (
272 subDe = readdir(subDir);
273 subDe != NULL;
274 subDe = readdir(subDir)
275 ) {
276 #define COPY_SAVEFILE(name) \
277 (strcmp(subDe->d_name, name) == 0) \
278 { \
279 strcpy(oldLocation, subDirLocation); \
280 strcat(oldLocation, name); \
281 strcpy(newLocation, output); \
282 strcat(newLocation, "saves/"); \
283 strcat(newLocation, name); \
284 PLATFORM_copyFile(oldLocation, newLocation); \
285 }
286 if COPY_SAVEFILE("unlock.vvv")
287 else if COPY_SAVEFILE("tsave.vvv")
288 else if COPY_SAVEFILE("qsave.vvv")
289 #undef COPY_SAVEFILE
290 }
291 }
292 }
293 #elif defined(_WIN32)
294 WIN32_FIND_DATA findHandle;
295 HANDLE hFind = NULL;
296 char fileSearch[MAX_PATH];
297
298 /* Same place, different layout. */
299 strcpy(oldDirectory, output);
300
301 /* In theory we don't need to worry about this, thanks case insensitivity!
302 sprintf(fileSearch, "%s\\Saves\\*.vvv", oldDirectory);
303 hFind = FindFirstFile(fileSearch, &findHandle);
304 if (hFind == INVALID_HANDLE_VALUE)
305 {
306 printf("Could not find directory %s\\Saves\\\n", oldDirectory);
307 }
308 else do
309 {
310 if ((findHandle.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
311 {
312 #define COPY_SAVEFILE(name) \
313 (strcmp(findHandle.cFileName, name) == 0) \
314 { \
315 strcpy(oldLocation, oldDirectory); \
316 strcat(oldLocation, "Saves\\"); \
317 strcat(oldLocation, name); \
318 strcpy(newLocation, output); \
319 strcat(newLocation, "saves\\"); \
320 strcat(newLocation, name); \
321 PLATFORM_copyFile(oldLocation, newLocation); \
322 }
323 if COPY_SAVEFILE("unlock.vvv")
324 else if COPY_SAVEFILE("tsave.vvv")
325 else if COPY_SAVEFILE("qsave.vvv")
326 #undef COPY_SAVEFILE
327 }
328 } while (FindNextFile(hFind, &findHandle));
329 */
330
331 sprintf(fileSearch, "%s\\*.vvvvvv", oldDirectory);
332 hFind = FindFirstFile(fileSearch, &findHandle);
333 if (hFind == INVALID_HANDLE_VALUE)
334 {
335 printf("Could not find directory %s\n", oldDirectory);
336 }
337 else do
338 {
339 if ((findHandle.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
340 {
341 strcpy(oldLocation, oldDirectory);
342 strcat(oldLocation, findHandle.cFileName);
343 strcpy(newLocation, output);
344 strcat(newLocation, "levels\\");
345 strcat(newLocation, findHandle.cFileName);
346 PLATFORM_copyFile(oldLocation, newLocation);
347 }
348 } while (FindNextFile(hFind, &findHandle));
349 #else
350 #error See PLATFORM_migrateSaveData
351 #endif
352 }
353
PLATFORM_copyFile(const char * oldLocation,const char * newLocation)354 void PLATFORM_copyFile(const char *oldLocation, const char *newLocation)
355 {
356 char *data;
357 long int length;
358
359 /* Read data */
360 FILE *file = fopen(oldLocation, "rb");
361 if (!file)
362 {
363 printf("Cannot open/copy %s\n", oldLocation);
364 return;
365 }
366 fseek(file, 0, SEEK_END);
367 length = ftell(file);
368 fseek(file, 0, SEEK_SET);
369 data = (char*) malloc(length);
370 fread(data, 1, length, file);
371 fclose(file);
372
373 /* Write data */
374 file = fopen(newLocation, "wb");
375 if (!file)
376 {
377 printf("Could not write to %s\n", newLocation);
378 free(data);
379 return;
380 }
381 fwrite(data, 1, length, file);
382 fclose(file);
383 free(data);
384
385 /* WTF did we just do */
386 printf("Copied:\n\tOld: %s\n\tNew: %s\n", oldLocation, newLocation);
387 }
388