1 /* Mednafen - Multi-system Emulator
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "mednafen.h"
19
20 #include <map>
21 #include <trio/trio.h>
22
23 #include "general.h"
24 #include "state.h"
25
26 #include <mednafen/hash/md5.h>
27 #include <mednafen/string/string.h>
28
29 namespace Mednafen
30 {
31 static std::string BaseDirectory;
32 static std::string FileBase;
33 static std::string FileExt; /* Includes the . character, as in ".nes" */
34 static std::string FileBaseDirectory;
35
MDFN_SetBaseDirectory(const std::string & dir)36 void MDFN_SetBaseDirectory(const std::string& dir)
37 {
38 BaseDirectory = dir;
39 }
40
MDFN_GetBaseDirectory(void)41 std::string MDFN_GetBaseDirectory(void)
42 {
43 return BaseDirectory;
44 }
45
46 typedef std::map<char, std::string> FSMap;
47
EvalPathFS(const std::string & fstring,FSMap & fmap)48 static std::string EvalPathFS(const std::string &fstring, /*const (won't work because entry created if char doesn't exist) */ FSMap &fmap)
49 {
50 std::string ret = "";
51 const char *str = fstring.c_str();
52 bool in_spec = false;
53
54 while(*str)
55 {
56 int c = *str;
57
58 if(!in_spec && c == '%')
59 in_spec = true;
60 else if(in_spec == true)
61 {
62 if(c == '%')
63 ret = ret + "%";
64 else
65 ret = ret + fmap[(char)c];
66 in_spec = false;
67 }
68 else
69 ret.push_back(c);
70
71 str++;
72 }
73
74 return ret;
75 }
76
MDFN_MakeFName(MakeFName_Type type,int id1,const char * cd1)77 std::string MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
78 {
79 std::string ret;
80 char numtmp[64];
81 FSMap fmap;
82
83 fmap['b'] = BaseDirectory;
84 fmap['z'] = PSS;
85
86 if(MDFNGameInfo)
87 {
88 fmap['d'] = FileBaseDirectory;
89 fmap['f'] = fmap['F'] = FileBase;
90
91 fmap['m'] = md5_context::asciistr(MDFNGameInfo->MD5, 0); // MD5 hash of the currently loaded game ONLY.
92
93 fmap['M'] = ""; // One with this empty, if file not found, then fill with the hash of the currently loaded game,
94 // followed by a period and go with that result.
95 fmap['e'] = FileExt;
96 fmap['s'] = MDFNGameInfo->shortname;
97
98 fmap['p'] = "";
99
100
101 fmap['x'] = ""; // Default extension(without period)
102 fmap['X'] = ""; // A merging of x and p
103 }
104
105
106 //printf("%s\n", EvalPathFS(std::string("%f.%m.sav"), fmap).c_str());
107
108 switch(type)
109 {
110 default:
111 break;
112
113
114 case MDFNMKF_MOVIE:
115 case MDFNMKF_STATE:
116 case MDFNMKF_SAV:
117 case MDFNMKF_SAVBACK:
118 {
119 std::string dir, fstring;
120
121 if(type == MDFNMKF_MOVIE)
122 {
123 dir = MDFN_GetSettingS("filesys.path_movie");
124 fstring = MDFN_GetSettingS("filesys.fname_movie");
125 fmap['x'] = "mcm";
126 }
127 else if(type == MDFNMKF_STATE)
128 {
129 dir = MDFN_GetSettingS("filesys.path_state");
130 fstring = MDFN_GetSettingS("filesys.fname_state");
131 fmap['x'] = (cd1 ? cd1 : "mcs");
132 }
133 else if(type == MDFNMKF_SAV)
134 {
135 dir = MDFN_GetSettingS("filesys.path_sav");
136 fstring = MDFN_GetSettingS("filesys.fname_sav");
137 fmap['x'] = cd1;
138 }
139 else if(type == MDFNMKF_SAVBACK)
140 {
141 dir = MDFN_GetSettingS("filesys.path_savbackup");
142 fstring = MDFN_GetSettingS("filesys.fname_savbackup");
143 fmap['x'] = cd1;
144 }
145
146 fmap['X'] = fmap['x'];
147
148 if(type == MDFNMKF_SAVBACK)
149 {
150 if(id1 < 0)
151 fmap['p'] = "C";
152 else
153 {
154 trio_snprintf(numtmp, sizeof(numtmp), "%u", id1);
155 fmap['p'] = numtmp;
156 }
157 }
158 else if(type != MDFNMKF_SAV && !cd1)
159 {
160 trio_snprintf(numtmp, sizeof(numtmp), "%d", id1);
161 fmap['p'] = numtmp;
162 }
163
164 if(fmap['X'].size() > 1 && fmap['p'].size())
165 fmap['X'] = fmap['X'].erase(fmap['X'].size() - 1) + fmap['p'];
166 //
167 //
168 if(!NVFS.is_absolute_path(dir))
169 dir = BaseDirectory + PSS + dir;
170
171 for(int i = 0; i < 2; i++)
172 {
173 ret = EvalPathFS(fstring, fmap);
174
175 if(!NVFS.is_absolute_path(ret))
176 ret = dir + PSS + ret;
177
178 if(!NVFS.finfo(ret, nullptr, false))
179 fmap['M'] = fmap['m'] + ".";
180 else
181 break;
182 }
183 }
184
185 NVFS.create_missing_dirs(ret);
186 break;
187
188
189 case MDFNMKF_SNAP_DAT:
190 case MDFNMKF_SNAP:
191 {
192 std::string dir = MDFN_GetSettingS("filesys.path_snap");
193 std::string fstring = MDFN_GetSettingS("filesys.fname_snap");
194
195 trio_snprintf(numtmp, sizeof(numtmp), "%04u", id1);
196
197 fmap['p'] = numtmp;
198
199 if(cd1)
200 fmap['x'] = cd1;
201
202 if(type == MDFNMKF_SNAP_DAT)
203 {
204 fmap['p'] = "counter";
205 fmap['x'] = "txt";
206 }
207
208 if(!NVFS.is_absolute_path(dir))
209 dir = BaseDirectory + PSS + dir;
210
211 ret = EvalPathFS(fstring, fmap);
212 if(!NVFS.is_absolute_path(ret))
213 ret = dir + PSS + ret;
214 }
215
216 NVFS.create_missing_dirs(ret);
217 break;
218
219
220 case MDFNMKF_CHEAT_TMP:
221 case MDFNMKF_CHEAT:
222 {
223 std::string basepath = MDFN_GetSettingS("filesys.path_cheat");
224
225 if(!NVFS.is_absolute_path(basepath))
226 basepath = BaseDirectory + PSS + basepath;
227
228 ret = basepath + PSS + MDFNGameInfo->shortname + "." + ((type == MDFNMKF_CHEAT_TMP) ? "tmpcht" : "cht");
229 }
230 break;
231
232
233 case MDFNMKF_IPS:
234 ret = FileBaseDirectory + PSS + FileBase + FileExt + ".ips";
235 break;
236
237
238 case MDFNMKF_FIRMWARE:
239 if(NVFS.is_absolute_path(cd1))
240 ret = cd1;
241 else
242 {
243 std::string overpath = MDFN_GetSettingS("filesys.path_firmware");
244
245 if(NVFS.is_absolute_path(overpath))
246 ret = overpath + PSS + cd1;
247 else
248 {
249 ret = BaseDirectory + PSS + overpath + PSS + cd1;
250
251 // For backwards-compatibility with < 0.9.0
252 if(!NVFS.finfo(ret, nullptr, false))
253 {
254 std::string new_ret = BaseDirectory + PSS + cd1;
255
256 if(NVFS.finfo(new_ret, nullptr, false))
257 ret = new_ret;
258 }
259 }
260 }
261 break;
262
263
264 case MDFNMKF_PALETTE:
265 {
266 std::string overpath = MDFN_GetSettingS("filesys.path_palette");
267 std::string eff_dir;
268
269 if(NVFS.is_absolute_path(overpath))
270 eff_dir = overpath;
271 else
272 eff_dir = BaseDirectory + PSS + overpath;
273
274 ret = eff_dir + PSS + FileBase + ".pal";
275
276 if(!NVFS.finfo(ret, nullptr, false))
277 {
278 ret = eff_dir + PSS + FileBase + "." + md5_context::asciistr(MDFNGameInfo->MD5, 0) + ".pal";
279
280 if(!NVFS.finfo(ret, nullptr, false))
281 ret = eff_dir + PSS + (cd1 ? cd1 : MDFNGameInfo->shortname) + ".pal";
282 }
283 }
284 break;
285
286
287 case MDFNMKF_PGCONFIG:
288 {
289 std::string overpath = MDFN_GetSettingS("filesys.path_pgconfig");
290 std::string eff_dir;
291
292 if(NVFS.is_absolute_path(overpath))
293 eff_dir = overpath;
294 else
295 eff_dir = BaseDirectory + PSS + overpath;
296
297 ret = eff_dir + PSS + FileBase + "." + MDFNGameInfo->shortname + ".cfg";
298 }
299 break;
300 }
301
302 return ret;
303 }
304
GetFileBase(const char * f)305 void GetFileBase(const char *f)
306 {
307 NVFS.get_file_path_components(f, &FileBaseDirectory, &FileBase, &FileExt);
308 }
309
310 }
311