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