initial commit, lordsawar source, slightly modified
[lordsawar] / src / File.cpp
1 // Copyright (C) 2000, 2001, 2002, 2003 Michael Bartl
2 // Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Ulf Lorenz
3 // Copyright (C) 2004, 2005, 2006 Andrea Paternesi
4 // Copyright (C) 2006, 2007, 2008, 2009 Ben Asselstine
5 // Copyright (C) 2007 Ole Laursen
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License as published by
9 //  the Free Software Foundation; either version 3 of the License, or
10 //  (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU Library General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
20 //  02110-1301, USA.
21
22 #include "config.h"
23
24 #include <iostream>
25 #include <string.h>
26 #include <algorithm>
27 #include <glibmm/fileutils.h>
28 #include <glibmm/ustring.h>
29 #include <glibmm/convert.h>
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <sys/stat.h>
33 #ifndef __WIN32__
34 #include <unistd.h>
35 #endif
36
37 #include "File.h"
38 #include "Configuration.h"
39 #include "defs.h"
40 #include "armyset.h"
41 #include "tileset.h"
42 #include "shieldset.h"
43 #include "cityset.h"
44
45 #define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<std::flush;}
46 //#define debug(x)
47
48 namespace
49 {
50     // returns a list of full paths of the immediate subdirs of path
51     std::list<std::string> get_immediate_subdirs(std::string path)
52     {
53         Glib::Dir dir(path);
54         std::list<std::string> dirlist;
55
56         for (Glib::Dir::iterator i = dir.begin(), end = dir.end();
57              i != end; ++i)
58         {
59             std::string entry = path + *i;
60             if (Glib::file_test(entry, Glib::FILE_TEST_IS_DIR))
61                 dirlist.push_back(entry);
62         }
63
64         return dirlist;
65     }
66
67     // returns a list of the XML file names in path with the ".xml" extension
68     // stripped
69     std::list<std::string> get_xml_files(std::string path, std::string ext)
70     {
71         std::list<std::string> retlist;
72         Glib::Dir dir(path);
73     
74         for (Glib::Dir::iterator i = dir.begin(), end = dir.end(); i != end; ++i)
75         {
76             std::string entry = *i;
77             std::string::size_type idx = entry.rfind(ext);
78             if (idx != std::string::npos && 
79                 idx == entry.length() - ext.length())
80             {
81                 entry.replace(idx, ext.length(), "");  //substitute the ".xml" with ""
82                 retlist.push_back(Glib::filename_to_utf8(path + entry));
83             }
84         }
85         return retlist;
86     }
87     
88     // returns a list of the XML file names in the immediate subdirs of path
89     // with the ".xml" extension stripped
90     std::list<std::string> get_xml_files_in_immediate_subdirs(std::string path, std::string ext)
91     {
92         std::list<std::string> retlist, dirlist = get_immediate_subdirs(path);
93         for (std::list<std::string>::iterator i = dirlist.begin(),
94                  end = dirlist.end(); i != end; ++i)
95         {
96             std::list<std::string> files = 
97               get_xml_files(File::add_slash_if_necessary(*i), ext);
98         
99             retlist.insert(retlist.end(), files.begin(), files.end());
100         }
101         return retlist;
102     }
103 }
104
105 std::string File::add_slash_if_necessary(std::string dir)
106 {
107   if (dir.c_str()[strlen(dir.c_str())-1] == '/')
108     return dir;
109   else
110     return dir + "/";
111 }
112
113 std::string File::getMiscFile(std::string filename)
114 {
115   return Configuration::s_dataPath + "/" + filename;
116 }
117
118 std::string File::getItemDescription()
119 {
120   return Configuration::s_dataPath + "/various/items/items.xml";
121 }
122
123 std::string File::getEditorFile(std::string filename)
124 {
125   return Configuration::s_dataPath + "/various/editor/" + filename + ".png";
126 }
127
128 std::string File::getMusicFile(std::string filename)
129 {
130   return std::string(Configuration::s_dataPath + "/music/" + filename.c_str());
131 }
132
133 std::string File::getDataPath()
134 {
135   return add_slash_if_necessary(Configuration::s_dataPath);
136 }
137
138 std::string File::getSavePath()
139 {
140   return add_slash_if_necessary(Configuration::s_savePath);
141 }
142
143 std::string File::getUserMapDir()
144 {
145   return add_slash_if_necessary(Configuration::s_savePath) + MAPDIR + "/";
146 }
147
148 std::string File::getMapDir()
149 {
150   return add_slash_if_necessary(Configuration::s_dataPath) + MAPDIR + "/";
151 }
152
153 std::string File::getUserMapFile(std::string file)
154 {
155   return getUserMapDir() + file;
156 }
157
158 std::string File::getMapFile(std::string file)
159 {
160   return getMapDir() + file;
161 }
162 std::list<std::string> File::scanUserMaps()
163 {
164   std::string path = File::getUserMapDir();
165     
166     std::list<std::string> retlist;
167     Glib::Dir dir(path);
168     
169     for (Glib::Dir::iterator i = dir.begin(), end = dir.end(); i != end; ++i)
170     {
171       std::string entry = *i;
172       std::string::size_type idx = entry.find(".map");
173       if (idx != std::string::npos)
174         {
175           if (entry == "random.map")
176             continue;
177           retlist.push_back(Glib::filename_to_utf8(entry));
178         }
179     }
180     
181     return retlist;
182 }
183
184 std::list<std::string> File::scanMaps()
185 {
186   std::string path = File::getMapDir();
187     
188     std::list<std::string> retlist;
189     Glib::Dir dir(path);
190     
191     for (Glib::Dir::iterator i = dir.begin(), end = dir.end(); i != end; ++i)
192     {
193       std::string entry = *i;
194       std::string::size_type idx = entry.find(".map");
195       if (idx != std::string::npos)
196         {
197             retlist.push_back(Glib::filename_to_utf8(entry));
198         }
199     }
200     
201     if (retlist.empty())
202     {
203       std::cerr << "Couldn't find a single map!" << std::endl;
204       std::cerr << "Please check the path settings in /etc/lordsawarrc or ~/.lordsawarrc" << std::endl;
205     }
206
207     return retlist;
208 }
209
210 std::string File::get_dirname(std::string path)
211 {
212   return Glib::path_get_dirname(path);
213 }
214 std::string File::get_basename(std::string path, bool keep_ext)
215 {
216   std::string file;
217   file = Glib::path_get_basename(path);
218   if (keep_ext)
219     return file;
220   //now strip everything past the last dot.
221   const char *tmp = strrchr (file.c_str(), '.');
222   if (!tmp)
223     return file;
224   int npos = tmp - file.c_str() + 1;
225   file = file.substr(0, npos - 1);
226   return file;
227 }
228 //copy_file taken from ardour-2.0rc2, gplv2+.
229 int File::copy (Glib::ustring from, Glib::ustring to)
230 {
231   std::ifstream in (from.c_str());
232   std::ofstream out (to.c_str());
233
234   if (!in)
235     return -1;
236
237   if (!out)
238     return -1;
239
240   out << in.rdbuf();
241
242   if (!in || !out) 
243     {
244       unlink (to.c_str());
245       return -1;
246     }
247
248   return 0;
249 }
250 bool File::create_dir(std::string dir)
251 {
252     struct stat testdir;
253 #ifndef __WIN32__
254     if (stat(dir.c_str(), &testdir) || !S_ISDIR(testdir.st_mode))
255     {
256         guint32 mask = 0755; //make directory only readable for user and group
257         if (mkdir(dir.c_str(), mask))
258           return false;
259     }
260 #else
261     return false;
262 #endif
263     return true;
264 }
265         
266 bool File::is_writable(std::string file)
267 {
268 #ifndef __WIN32__
269   if (access (file.c_str(), W_OK) != 0)
270     return false;
271   else
272     return true;
273 #endif
274   return false;
275 }
276
277 bool File::exists(std::string f)
278 {
279   FILE *fileptr = fopen (f.c_str(), "r");
280   bool retval = fileptr != NULL;
281   if (fileptr)
282     fclose(fileptr);
283   return retval;
284 }
285
286 //armysets 
287
288 std::string File::getArmysetDir()
289 {
290   return add_slash_if_necessary(Configuration::s_dataPath) + ARMYSETDIR + "/";
291 }
292
293 std::string File::getUserArmysetDir()
294 {
295   std::string dir =  getSavePath() + ARMYSETDIR + "/";
296   return dir;
297 }
298
299 std::list<std::string> File::scanFiles(std::string dir, std::string extension)
300 {
301   return get_xml_files_in_immediate_subdirs(dir, extension);
302 }
303
304 std::string File::getTilesetDir()
305 {
306   return add_slash_if_necessary(Configuration::s_dataPath) + TILESETDIR + "/";
307 }
308
309 std::string File::getUserTilesetDir()
310 {
311   std::string dir = getSavePath() + TILESETDIR + "/";
312   return dir;
313 }
314
315 //shieldsets
316 std::string File::getShieldsetDir()
317 {
318   return add_slash_if_necessary(Configuration::s_dataPath) + SHIELDSETDIR + "/";
319 }
320
321 std::string File::getUserShieldsetDir()
322 {
323   std::string dir = getSavePath() + SHIELDSETDIR + "/";
324   return dir;
325 }
326
327 std::string File::getCitysetDir()
328 {
329   return add_slash_if_necessary(Configuration::s_dataPath) + CITYSETDIR + "/";
330 }
331
332 std::string File::getUserCitysetDir()
333 {
334   std::string dir = getSavePath() + CITYSETDIR + "/";
335   return dir;
336 }
337
338
339 bool File::nameEndsWith(std::string filename, std::string extension)
340 {
341   std::string::size_type idx = filename.rfind(extension);
342   if (idx == std::string::npos)
343     return false;
344   if (idx == filename.length() - extension.length())
345     return true;
346   return false;
347 }
348
349 void File::erase(std::string filename)
350 {
351   remove(filename.c_str());
352 }
353
354 void File::erase_dir(std::string filename)
355 {
356   rmdir(filename.c_str());
357 }
358 std::string File::getSetConfigurationFilename(std::string dir, std::string subdir, std::string ext)
359 {
360   return add_slash_if_necessary(dir) + subdir + "/" + subdir + ext;
361 }