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