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
23 * This file containing callbacks for Physfs (replacing the old pak system)
30 PhysFS::PhysFS(char* in_argv
)
32 if (!PHYSFS_init(in_argv
)) PhysFSInitError();
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
);
39 if (!SetWriteDir("./savedata")) SetWriteWarning("savedata");
40 if (!PHYSFS_addToSearchPath("savedata", 0)) AddPathWarning("savedata");
43 if (!PHYSFS_addToSearchPath("data", 1)) AddPathWarning("data");
46 if (!PHYSFS_addToSearchPath(DATADIR
, 1)) AddPathWarning(DATADIR
);
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());
65 throw std::runtime_error("PhysFS: Couldn't open file: " + file
);
70 SDL_RWops
* PhysFS::RWopsFile(const std::string
& file
)
72 PHYSFS_file
* filehandler
= OpenFile(file
);
74 SDL_RWops
* rw
= new SDL_RWops
;
76 rw
->hidden
.unknown
.data1
= filehandler
;
79 rw
->write
= RWopsWrite
;
80 rw
->close
= RWopsClose
;
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
);
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);
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
);
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());
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());
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
;
181 while (dir
.npos
!= (pos
= dir
.find('/', ++pos
)))
186 std::string
* substrs
= new std::string
[num
];
189 for (unsigned int i
= 0; i
< num
; i
++)
192 pos2
= dir
.find('/', ++pos
);
193 substrs
[i
] = dir
.substr(pos
, i
!= num
-1 ? pos2
- pos
: 999);
196 std::string basepath
;
200 if (num
<= 0) return false;
203 for (unsigned int i
= 0; i
< num
; i
++) basepath
+= substrs
[i
] + ((i
!= (num
-1)) ? "/" : "");
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
;
224 while (file
.npos
!= (pos
= file
.find('/', ++pos
)))
230 for (unsigned int i
= 0; i
< num
; i
++)
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
;
247 res
= PHYSFS_seek(file
, offset
);
250 res
= PHYSFS_seek(file
, PHYSFS_tell(file
) + offset
);
253 res
= PHYSFS_seek(file
, PHYSFS_fileLength(file
) + offset
);
262 error
<< "Error seeking in file: " << PHYSFS_getLastError() << std::endl
;
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
);
277 int PhysFS::RWopsClose(SDL_RWops
* context
)
279 PHYSFS_file
* file
= (PHYSFS_file
*) context
->hidden
.unknown
.data1
;
287 int PhysFS::RWopsWrite(SDL_RWops
* context
, const void *ptr
, int size
, int num
)
293 // Copyright 2006 Matthias Braun
295 PhysFS::IStreambuf::IStreambuf(const std::string
& filename
)
297 file
= PhysFS::OpenFile(filename
);
300 PhysFS::IStreambuf::~IStreambuf()
305 int PhysFS::IStreambuf::underflow()
309 return traits_type::eof();
312 PHYSFS_sint64 bytesread
= PHYSFS_read(file
, buf
, 1, sizeof(buf
));
315 return traits_type::eof();
317 setg(buf
, buf
, buf
+ bytesread
);
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
334 PhysFS::IStreambuf::pos_type
PhysFS::IStreambuf::seekoff(off_type off
, std::ios_base::seekdir dir
, std::ios_base::openmode mode
)
337 PHYSFS_sint64 ptell
= PHYSFS_tell(file
);
341 case std::ios_base::beg
:
343 case std::ios_base::cur
:
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());
348 case std::ios_base::end
:
349 pos
+= static_cast<off_type
> (PHYSFS_fileLength(file
));
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());
365 std::cerr
<< "[ERROR] PhysFS: Couldn't open file for writing: " << file
<< std::endl
;
369 setp(buf
, buf
+sizeof(buf
));
372 PhysFS::OStreambuf::~OStreambuf()
378 int PhysFS::OStreambuf::overflow(int c
)
382 if(pbase() == pptr())
385 size_t size
= pptr() - pbase();
386 PHYSFS_sint64 res
= PHYSFS_write(file
, pbase(), 1, size
);
388 return traits_type::eof();
390 if(c
!= traits_type::eof())
392 PHYSFS_sint64 res
= PHYSFS_write(file
, &c2
, 1, 1);
394 return traits_type::eof();
397 setp(buf
, buf
+ res
);
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()
417 //---------------------------------------------------------------------------
419 PhysFS::OStream::OStream(const std::string
& filename
) : std::ostream(new PhysFS::OStreambuf(filename
))
423 PhysFS::OStream::~OStream()
428 //----------------------------------------------------------------------------
429 // End of Matze's code
431 PhysFS
* PhysFS::instance
= NULL
;