Debug system v2 -- now, it supports debug levels, there's a global level, but overrid...
[dbw.git] / src / physfs / physfs.cpp
blob29d3bb229bd6e01930018e068587f77f8d20f13f
1 /*
2 Copyright © 2007-2008 Kővágó Zoltán <DirtY.iCE.hu@gmail.com>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 /** @file physfs/physfs.cpp
22 * Physfs functions
23 * This file containing callbacks for Physfs (replacing the old pak system)
26 #include "config.h"
27 #include "physfs.hpp"
28 #include <stdexcept>
30 PhysFS::PhysFS(char* in_argv)
32 if (!PHYSFS_init(in_argv)) PhysFSInitError();
34 #ifdef UNIX
35 std::string userdir = (std::string) PHYSFS_getUserDir() + ".dirtystudios/dirtyblobwars";
36 if (!SetWriteDir(userdir)) SetWriteWarning(userdir);
37 if (!PHYSFS_addToSearchPath(userdir.c_str(), 0)) AddPathWarning(userdir);
38 #else
39 if (!SetWriteDir("./savedata")) SetWriteWarning("savedata");
40 if (!PHYSFS_addToSearchPath("savedata", 0)) AddPathWarning("savedata");
41 #endif
43 if (!PHYSFS_addToSearchPath("data", 1)) AddPathWarning("data");
45 #ifdef UNIX
46 if (!PHYSFS_addToSearchPath(DATADIR, 1)) AddPathWarning(DATADIR);
47 #endif
51 PhysFS::~PhysFS()
53 //BOOOM-BOOM-BOOM!!!
54 PHYSFS_deinit();
57 PHYSFS_file * PhysFS::OpenFile(const std::string& file)
59 if (!PHYSFS_exists(file.c_str()))
60 throw std::runtime_error("PhysFS: File doesn't exists: " + file);
63 PHYSFS_file* filehandler = PHYSFS_openRead(file.c_str());
64 if (!filehandler)
65 throw std::runtime_error("PhysFS: Couldn't open file: " + file);
67 return filehandler;
70 SDL_RWops * PhysFS::RWopsFile(const std::string& file)
72 PHYSFS_file * filehandler = OpenFile(file);
74 SDL_RWops * rw = new SDL_RWops;
75 rw->type = 0;
76 rw->hidden.unknown.data1 = filehandler;
77 rw->seek = RWopsSeek;
78 rw->read = RWopsRead;
79 rw->write = RWopsWrite;
80 rw->close = RWopsClose;
82 return rw;
85 int PhysFS::ReadFile(const std::string& file, char ** pointer, const int max)
87 PHYSFS_file* filehandler = OpenFile(file);
89 int filesize = max ? max : PHYSFS_fileLength(filehandler);
90 *pointer = new char[filesize];
92 PHYSFS_read(filehandler, *pointer, 1, filesize);
93 PHYSFS_close(filehandler);
95 return filesize;
98 std::stringbuf * PhysFS::ReadFile(const std::string& file)
100 PHYSFS_file * filehandler = OpenFile(file);
101 int filesize = PHYSFS_fileLength(filehandler);
102 char * pointer = new char[filesize];
104 PHYSFS_read(filehandler, pointer, 1, filesize);
105 //std::string in(pointer, filesize);
106 std::stringbuf * sb = new std::stringbuf(std::string(pointer, filesize));
107 //sb->pubsetbuf(pointer, filesize);
109 delete[] pointer;
111 return sb;
114 int PhysFS::ReadFileIntoPointer(const std::string& file, char * pointer, const int max)
116 PHYSFS_file* filehandler = OpenFile(file);
118 int filesize = max ? max : PHYSFS_fileLength(filehandler);
120 filesize = PHYSFS_read(filehandler, pointer, 1, filesize);
121 PHYSFS_close(filehandler);
123 return filesize;
126 void PhysFS::WriteFile(const std::string& file, const std::stringbuf& sb)
128 if (file.npos != file.find('/', 0)) MakeDirForFile(file);
129 PHYSFS_file* filehandler = PHYSFS_openWrite(file.c_str());
130 if (!filehandler)
131 throw std::runtime_error("PhysFS: Couldn't open file for writing: " + file);
134 std::string str = sb.str();
135 PHYSFS_write(filehandler, str.c_str(), 1, str.size());
136 PHYSFS_close(filehandler);
139 void PhysFS::WriteFile(const std::string& file, const char * pointer, const int length)
141 PHYSFS_file* filehandler = PHYSFS_openWrite(file.c_str());
142 if (!filehandler)
143 throw std::runtime_error("PhysFS: Couldn't open file for writing: " + file);
145 PHYSFS_write(filehandler, pointer, 1, length);
146 PHYSFS_close(filehandler);
149 void PhysFS::PhysFSInitError()
151 error << "Failed to initialize PhysFS!" << std::endl;
152 error << "Make sure you installed PhysFS correctly, and reinstall DirtY BLoB WaRs" <<std::endl;
153 error << "For more info, read the README file, or contact us." << std::endl;
154 char* error_str = (char*) PHYSFS_getLastError();
155 if (error_str == '\0') error_str = (char *) "Unknown";
156 error << "The error was: " << error_str << std::endl << std::endl;
157 throw std::runtime_error("PhysFS initialization failed");
160 void PhysFS::AddPathWarning(const std::string& path)
162 warning << "Failed to add '" << path << "' to the search path." <<std::endl
163 << "The game might not run correctly." << std::endl
164 << "PhysFS reports: " << PHYSFS_getLastError() << std::endl;
167 void PhysFS::SetWriteWarning(const std::string& path)
169 warning << "Failed to set '" << path << "' as write dir!" << std::endl
170 << "The game can't save your options and your state." << std::endl
171 << "PhysFS reports: " << PHYSFS_getLastError() << std::endl;
174 bool PhysFS::SetWriteDir(const std::string& dir)
176 if (PHYSFS_setWriteDir(dir.c_str())) return true;
178 unsigned int pos, pos2 , num, num2;
179 num = num2 = 0;
180 pos = -1;
181 while (dir.npos != (pos = dir.find('/', ++pos)))
183 num++;
185 num++;
186 std::string * substrs = new std::string[num];
188 pos2 = -1;
189 for (unsigned int i = 0; i < num; i++)
191 pos = pos2;
192 pos2 = dir.find('/', ++pos);
193 substrs[i] = dir.substr(pos, i != num-1 ? pos2 - pos : 999);
196 std::string basepath;
197 num2 = num;
200 if (num <= 0) return false;
202 basepath = "";
203 for (unsigned int i = 0; i < num; i++) basepath += substrs[i] + ((i != (num-1)) ? "/" : "");
205 num--;
206 } while (!PHYSFS_setWriteDir(basepath.c_str()));
208 std::string path2 = "";
209 for (unsigned int i = 1; i < (num2-num); i++)
211 path2 += (i != 1 ? "/" : "") + substrs[num+i];
212 debug("physfs", 2) << "Making directory:: '" << basepath << "' :: '" << path2 << "'" << std::endl;
213 if (!PHYSFS_mkdir(path2.c_str())) return false;
216 return PHYSFS_setWriteDir(dir.c_str());
219 void PhysFS::MakeDirForFile(const std::string& file)
221 unsigned int num, pos, pos2;
222 num = 0;
223 pos = pos2 = -1;
224 while (file.npos != (pos = file.find('/', ++pos)))
226 num++;
229 pos2 = -1;
230 for (unsigned int i = 0; i < num; i++)
232 pos = pos2;
233 pos2 = file.find('/', ++pos);
234 PHYSFS_mkdir(file.substr(pos, pos2 - pos).c_str());
238 /* PhysFS reading funcs for SDL_RWops
239 Copyright 2006 Matthias Braun <mattze@braunis.de> */
241 int PhysFS::RWopsSeek(SDL_RWops* context, int offset, int whence)
243 PHYSFS_file* file = (PHYSFS_file*) context->hidden.unknown.data1;
244 int res;
245 switch(whence) {
246 case SEEK_SET:
247 res = PHYSFS_seek(file, offset);
248 break;
249 case SEEK_CUR:
250 res = PHYSFS_seek(file, PHYSFS_tell(file) + offset);
251 break;
252 case SEEK_END:
253 res = PHYSFS_seek(file, PHYSFS_fileLength(file) + offset);
254 break;
255 default:
256 res = 0;
257 exit(1);
258 break;
261 if(res == 0) {
262 error << "Error seeking in file: " << PHYSFS_getLastError() << std::endl;
263 return -1;
266 return (int) PHYSFS_tell(file);
269 int PhysFS::RWopsRead(SDL_RWops* context, void* ptr, int size, int maxnum)
271 PHYSFS_file* file = (PHYSFS_file*) context->hidden.unknown.data1;
273 int res = PHYSFS_read(file, ptr, size, maxnum);
274 return res;
277 int PhysFS::RWopsClose(SDL_RWops* context)
279 PHYSFS_file* file = (PHYSFS_file*) context->hidden.unknown.data1;
281 PHYSFS_close(file);
282 delete context;
284 return 0;
287 int PhysFS::RWopsWrite(SDL_RWops* context, const void *ptr, int size, int num)
289 return -1;
292 // PhysFS streaming
293 // Copyright 2006 Matthias Braun
295 PhysFS::IStreambuf::IStreambuf(const std::string& filename)
297 file = PhysFS::OpenFile(filename);
300 PhysFS::IStreambuf::~IStreambuf()
302 PHYSFS_close(file);
305 int PhysFS::IStreambuf::underflow()
307 if(PHYSFS_eof(file))
309 return traits_type::eof();
312 PHYSFS_sint64 bytesread = PHYSFS_read(file, buf, 1, sizeof(buf));
313 if(bytesread <= 0)
315 return traits_type::eof();
317 setg(buf, buf, buf + bytesread);
319 return buf[0];
322 PhysFS::IStreambuf::pos_type PhysFS::IStreambuf::seekpos(pos_type pos, std::ios_base::openmode)
324 if(PHYSFS_seek(file, static_cast<PHYSFS_uint64> (pos)) == 0)
326 return pos_type(off_type(-1));
329 // the seek invalidated the buffer
330 setg(buf, buf, buf);
331 return pos;
334 PhysFS::IStreambuf::pos_type PhysFS::IStreambuf::seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode mode)
336 off_type pos = off;
337 PHYSFS_sint64 ptell = PHYSFS_tell(file);
339 switch(dir)
341 case std::ios_base::beg:
342 break;
343 case std::ios_base::cur:
344 if(off == 0)
345 return static_cast<pos_type> (ptell) - static_cast<pos_type> (egptr() - gptr());
346 pos += static_cast<off_type> (ptell) - static_cast<off_type> (egptr() - gptr());
347 break;
348 case std::ios_base::end:
349 pos += static_cast<off_type> (PHYSFS_fileLength(file));
350 break;
351 default:
352 return pos_type(off_type(-1));
355 return seekpos(static_cast<pos_type> (pos), mode);
358 //---------------------------------------------------------------------------
360 PhysFS::OStreambuf::OStreambuf(const std::string& filename)
362 file = PHYSFS_openWrite(filename.c_str());
363 if(!file)
365 std::cerr << "[ERROR] PhysFS: Couldn't open file for writing: " << file << std::endl;
366 exit(1);
369 setp(buf, buf+sizeof(buf));
372 PhysFS::OStreambuf::~OStreambuf()
374 sync();
375 PHYSFS_close(file);
378 int PhysFS::OStreambuf::overflow(int c)
380 char c2 = (char)c;
382 if(pbase() == pptr())
383 return 0;
385 size_t size = pptr() - pbase();
386 PHYSFS_sint64 res = PHYSFS_write(file, pbase(), 1, size);
387 if(res <= 0)
388 return traits_type::eof();
390 if(c != traits_type::eof())
392 PHYSFS_sint64 res = PHYSFS_write(file, &c2, 1, 1);
393 if(res <= 0)
394 return traits_type::eof();
397 setp(buf, buf + res);
398 return 0;
401 int PhysFS::OStreambuf::sync()
403 return overflow(traits_type::eof());
406 //---------------------------------------------------------------------------
408 PhysFS::IStream::IStream(const std::string& filename) : std::istream(new PhysFS::IStreambuf(filename))
412 PhysFS::IStream::~IStream()
414 delete rdbuf();
417 //---------------------------------------------------------------------------
419 PhysFS::OStream::OStream(const std::string& filename) : std::ostream(new PhysFS::OStreambuf(filename))
423 PhysFS::OStream::~OStream()
425 delete rdbuf();
428 //----------------------------------------------------------------------------
429 // End of Matze's code
431 PhysFS* PhysFS::instance = NULL;