1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <SDL2/SDL.h>
6
7 #if defined(_WIN32) || defined(WIN32)
8 #include <shlobj.h> //SHCreateDirectoryEx
9 #else
10 #include <sys/stat.h> // mkdir
11 #endif
12
13 #include "resources/pathmanager.h"
14 #include "utils/log.h"
15
16 // Files
17 static const char* logfile_name = "openomf.log";
18 static const char* configfile_name = "openomf.conf";
19 static const char* scorefile_name = "SCORES.DAT";
20 static const char* savegamedir_name = "save/";
21 static char errormessage[128];
22
23 // Lists
24 static char* local_paths[NUMBER_OF_LOCAL_PATHS];
25 static char* resource_paths[NUMBER_OF_RESOURCES];
26
27 // Build directory
local_path_build(int path_id,const char * path,const char * ext)28 static void local_path_build(int path_id, const char *path, const char *ext) {
29 int len = strlen(path) + strlen(ext) + 1;
30 local_paths[path_id] = realloc(local_paths[path_id], len);
31 sprintf(local_paths[path_id], "%s%s", path, ext);
32 }
resource_path_build(int path_id,const char * path,const char * ext)33 static void resource_path_build(int path_id, const char *path, const char *ext) {
34 int len = strlen(path) + strlen(ext) + 1;
35 resource_paths[path_id] = realloc(resource_paths[path_id], len);
36 sprintf(resource_paths[path_id], "%s%s", path, ext);
37 }
38
str_ends_with_sep(const char * str)39 int str_ends_with_sep(const char *str) {
40 int pos = strlen(str) - 1;
41 return (str[pos] == '/' || str[pos] == '\\');
42 }
43
44 // Makes sure resource file exists
pm_validate_resources()45 int pm_validate_resources() {
46 for(int i = 0; i < NUMBER_OF_RESOURCES; i++) {
47 const char *testfile = pm_get_resource_path(i);
48 if(access(testfile, F_OK) == -1) {
49 sprintf(errormessage, "Missing file %s.", testfile);
50 return 1;
51 }
52 }
53 return 0;
54 }
55
pm_init()56 int pm_init() {
57 char *local_base_dir;
58 char *bin_base_dir;
59
60 // Clear everything
61 errormessage[0] = 0;
62 memset(local_paths, 0, sizeof(local_paths));
63 memset(resource_paths, 0, sizeof(resource_paths));
64
65 // Find local basedir
66 local_base_dir = pm_get_local_base_dir();
67 if(local_base_dir == NULL) {
68 goto error_0;
69 }
70
71 // Other paths
72 local_path_build(LOG_PATH, local_base_dir, logfile_name);
73 local_path_build(CONFIG_PATH, local_base_dir, configfile_name);
74 local_path_build(SCORE_PATH, local_base_dir, scorefile_name);
75 local_path_build(SAVE_PATH, local_base_dir, savegamedir_name);
76
77 // Set default base dirs for resources and plugins
78 int m_ok = 0;
79 if(pm_in_release_mode()) {
80 // where is the openomf binary, if this call fails we will look for resources in ./resources
81 bin_base_dir = SDL_GetBasePath();
82 if(bin_base_dir != NULL) {
83 if(!strcasecmp(SDL_GetPlatform(), "Windows")) {
84 // on windows, the resources will be in ./resources, relative to the binary
85 local_path_build(RESOURCE_PATH, bin_base_dir, "resources\\");
86 local_path_build(PLUGIN_PATH, bin_base_dir, "plugins\\");
87 m_ok = 1;
88 } else if(!strcasecmp(SDL_GetPlatform(), "FreeBSD")) {
89 // on linux, the resources will be in ../share/games/openomf, relative to the binary
90 // so if openomf is installed to /usr/local/bin,
91 // the resources will be in /usr/local/share/games/openomf
92 local_path_build(RESOURCE_PATH, "/usr/local", "/share/openomf/");
93 local_path_build(PLUGIN_PATH, bin_base_dir, "../lib/openomf/");
94 m_ok = 1;
95 } else if(!strcasecmp(SDL_GetPlatform(), "Mac OS X")) {
96 // on OSX, GetBasePath returns the 'Resources' directory
97 // if run from an app bundle, so we can use this as-is
98 local_path_build(RESOURCE_PATH, bin_base_dir, "");
99 local_path_build(PLUGIN_PATH, bin_base_dir, "plugins/");
100 m_ok = 1;
101 }
102 // any other platform will look in ./resources
103 SDL_free(bin_base_dir);
104 }
105 }
106
107 // Set default resource and plugins paths
108 if(!m_ok) {
109 if(!strcasecmp(SDL_GetPlatform(), "Windows")) {
110 local_path_build(RESOURCE_PATH, "resources\\", "");
111 local_path_build(PLUGIN_PATH, "plugins\\", "");
112 } else {
113 local_path_build(RESOURCE_PATH, "resources/", "");
114 local_path_build(PLUGIN_PATH, "plugins/", "");
115 }
116 }
117
118 char *platform_sep = "/";
119 if(!strcasecmp(SDL_GetPlatform(), "Windows")) {
120 platform_sep = "\\";
121 }
122
123 // check if we have overrides from the environment
124 char *resource_env = getenv("OPENOMF_RESOURCE_DIR");
125 if (resource_env) {
126 char *ext = str_ends_with_sep(resource_env) ? "" : platform_sep;
127 local_path_build(RESOURCE_PATH, resource_env, ext);
128 }
129
130 char *plugin_env = getenv("OPENOMF_PLUGIN_DIR");
131 if (plugin_env) {
132 char *ext = str_ends_with_sep(plugin_env) ? "" : platform_sep;
133 local_path_build(PLUGIN_PATH, plugin_env, ext);
134 }
135
136
137 // Set resource paths
138 for(int i = 0; i < NUMBER_OF_RESOURCES; i++) {
139 resource_path_build(i,
140 pm_get_local_path(RESOURCE_PATH),
141 get_resource_file(i));
142 }
143
144 // Check resources
145 if(pm_validate_resources() != 0) {
146 goto error_1;
147 }
148
149 // All done
150 free(local_base_dir);
151 return 0;
152
153 error_1:
154 pm_free();
155 free(local_base_dir);
156 error_0:
157 return 1;
158 }
159
pm_log()160 void pm_log() {
161 // Debug info
162 for(unsigned int i = 0; i < NUMBER_OF_LOCAL_PATHS; i++) {
163 DEBUG("%s: %s",
164 pm_get_local_path_type_name(i),
165 pm_get_local_path(i));
166 }
167 }
168
pm_free()169 void pm_free() {
170 for(int i = 0; i < NUMBER_OF_RESOURCES; i++) {
171 free(resource_paths[i]);
172 }
173 for(int i = 0; i < NUMBER_OF_LOCAL_PATHS; i++) {
174 free(local_paths[i]);
175 }
176 }
177
pm_get_errormsg()178 const char* pm_get_errormsg() {
179 return errormessage;
180 }
181
pm_in_debug_mode()182 int pm_in_debug_mode() {
183 #ifdef DEBUGMODE
184 return 1;
185 #else
186 return 0;
187 #endif
188 }
189
pm_in_release_mode()190 int pm_in_release_mode() {
191 if(!pm_in_portable_mode() && !pm_in_debug_mode()) {
192 return 1;
193 }
194 return 0;
195 }
196
pm_in_portable_mode()197 int pm_in_portable_mode() {
198 if(access(configfile_name, F_OK) != -1) {
199 return 1;
200 }
201 return 0;
202 }
203
pm_get_local_base_dir()204 char* pm_get_local_base_dir() {
205 char *out = NULL;
206 if(pm_in_portable_mode()) {
207 out = malloc(1);
208 out[0] = 0;
209 return out;
210 }
211
212 // Attempt to open up locally writable directory
213 char *sdl_path = SDL_GetPrefPath("openomfproject", "OpenOMF");
214 if(sdl_path == NULL) {
215 sprintf(errormessage, "Error getting config path: %s", SDL_GetError());
216 return NULL;
217 }
218 out = malloc(strlen(sdl_path)+1);
219 strcpy(out, sdl_path);
220 SDL_free(sdl_path);
221
222 // Ensure the path exists before continuing on
223 // XXX shouldn't SDL_GetPrefPath automatically create the path if it doesn't exist?
224 #if defined(_WIN32) || defined(WIN32)
225 int sherr = SHCreateDirectoryEx(NULL, out, NULL);
226 if(sherr == ERROR_FILE_EXISTS) {
227 sprintf(errormessage, "Please delete this file and relaunch OpenOMF: %s", out);
228 return NULL;
229 } else if(sherr != ERROR_SUCCESS && sherr != ERROR_ALREADY_EXISTS) {
230 sprintf(errormessage, "Failed to create config path: %s", out);
231 return NULL;
232 }
233 #endif
234
235 // All done
236 return out;
237 }
238
pm_get_local_path(unsigned int local_id)239 const char* pm_get_local_path(unsigned int local_id) {
240 if(local_id >= NUMBER_OF_LOCAL_PATHS) {
241 return NULL;
242 }
243 return local_paths[local_id];
244 }
245
pm_get_resource_path(unsigned int resource_id)246 const char* pm_get_resource_path(unsigned int resource_id) {
247 if(resource_id >= NUMBER_OF_RESOURCES) {
248 return NULL;
249 }
250 return resource_paths[resource_id];
251 }
252
pm_get_local_path_type_name(unsigned int path_id)253 const char* pm_get_local_path_type_name(unsigned int path_id) {
254 switch(path_id) {
255 case RESOURCE_PATH: return "RESOURCE_PATH";
256 case PLUGIN_PATH: return "PLUGIN_PATH";
257 case CONFIG_PATH: return "CONFIG_PATH";
258 case LOG_PATH: return "LOG_PATH";
259 case SCORE_PATH: return "SCORE_PATH";
260 case SAVE_PATH: return "SAVE_PATH";
261 }
262 return "UNKNOWN";
263 }
264
pm_create_dir(const char * dirname)265 int pm_create_dir(const char* dirname) {
266 #if defined(_WIN32) || defined(WIN32)
267 if(SHCreateDirectoryEx(NULL, dirname, NULL) != ERROR_SUCCESS) {
268 PERROR("Error while attempting to create directory '%s'.", dirname);
269 return 1;
270 }
271 #else
272 if(mkdir(dirname, 0755) != 0) {
273 PERROR("Error while attempting to create directory '%s'.", dirname);
274 return 1;
275 }
276 #endif
277 return 0;
278 }
279