├── .gitignore ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── include └── physfs.hpp ├── src ├── CMakeLists.txt └── physfs.cpp └── test ├── CMakeLists.txt └── physfs_test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeFiles 2 | Makefile 3 | *.a 4 | *.cmake 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(PhysFS++) 3 | enable_testing() 4 | include_directories(include) 5 | add_subdirectory(src) 6 | add_subdirectory(test) 7 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2013 Kevin Howell and others. 3 | 4 | This software is provided 'as-is', without any express or implied warranty. 5 | In no event will the authors be held liable for any damages arising from 6 | the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software in a 14 | product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | Kevin Howell 23 | 24 | This library wraps the C library PhysicsFS, written by Ryan C. Gordon and 25 | others. See http://icculus.org/physfs/. Its LICENSE (from the time of writing) 26 | is reproduced below: 27 | 28 | Copyright (c) 2001-2011 Ryan C. Gordon and others. 29 | 30 | This software is provided 'as-is', without any express or implied warranty. 31 | In no event will the authors be held liable for any damages arising from 32 | the use of this software. 33 | 34 | Permission is granted to anyone to use this software for any purpose, 35 | including commercial applications, and to alter it and redistribute it 36 | freely, subject to the following restrictions: 37 | 38 | 1. The origin of this software must not be misrepresented; you must not 39 | claim that you wrote the original software. If you use this software in a 40 | product, an acknowledgment in the product documentation would be 41 | appreciated but is not required. 42 | 43 | 2. Altered source versions must be plainly marked as such, and must not be 44 | misrepresented as being the original software. 45 | 46 | 3. This notice may not be removed or altered from any source distribution. 47 | 48 | Ryan C. Gordon 49 | 50 | 51 | 52 | 53 | Notes, separate from the license. This is not legal advice. 54 | 55 | Versions of PhysicsFS prior to 0.1.9 are licensed under the GNU Lesser General 56 | Public License, which restricts you significantly more. For your own safety, 57 | please make sure you've got 0.1.9 or later if you plan to use physfs in a 58 | commercial or closed-source project. 59 | 60 | Optional pieces of PhysicsFS may fall under other licenses, please consult 61 | your lawyer for legal advice, which this is not... 62 | 63 | lzma: if you enable LZMA (7zip) support, PhysicsFS uses the lzma sdk. 64 | It uses the LGPL license, with exceptions for closed-source programs. 65 | Please see lzma/lzma.txt for details. 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PhysFS++ 2 | ======== 3 | 4 | PhysFS++ is a C++ wrapper for the excellent [PhysicsFS library][1] by Ryan C. 5 | Gordon and others. 6 | 7 | [1]: http://icculus.org/physfs 8 | 9 | It is licensed under the zlib license - same as PhysicsFS (at the time of 10 | writing). 11 | 12 | Requirements 13 | ============ 14 | CMake for building, and, of course, the PhysicsFS library. 15 | 16 | Features 17 | ======== 18 | The wrapper simply wraps most functions in a PhysFS namespace, and gives them 19 | C++ signatures (`std::string` rather than `const char *`). 20 | 21 | Additionally: 22 | - Functions that are related to byte order conversions are placed in the 23 | PhysFS::Util namespace. 24 | - Instead of replicating `PHYSFS_openRead`, `PHYSFS_openWrite`, and 25 | `PHYSFS_openAppend`, files are opened as streams using `PhysFS::ifstream` and 26 | `PhysFS::ofstream`. 27 | - ofstream's constructor takes a mode, which specifies either append or write. 28 | - Both ifstream and ofstream are standard streams, and only have an extra 29 | method - `length`, which calls `PHYSFS_fileLength`. 30 | -------------------------------------------------------------------------------- /include/physfs.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_PHYSFS_HPP_ 2 | #define _INCLUDE_PHYSFS_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace PhysFS { 10 | 11 | typedef enum { 12 | READ, 13 | WRITE, 14 | APPEND 15 | } mode; 16 | 17 | using std::string; 18 | 19 | typedef std::vector StringList; 20 | 21 | typedef PHYSFS_uint8 uint8; 22 | 23 | typedef PHYSFS_sint8 sint8; 24 | 25 | typedef PHYSFS_uint16 uint16; 26 | 27 | typedef PHYSFS_sint16 sint16; 28 | 29 | typedef PHYSFS_uint32 uint32; 30 | 31 | typedef PHYSFS_sint32 sint32; 32 | 33 | typedef PHYSFS_uint64 uint64; 34 | 35 | typedef PHYSFS_sint64 sint64; 36 | 37 | typedef PHYSFS_StringCallback StringCallback; 38 | 39 | typedef PHYSFS_EnumFilesCallback EnumFilesCallback; 40 | 41 | typedef PHYSFS_Version Version; 42 | 43 | typedef PHYSFS_Allocator Allocator; 44 | 45 | typedef PHYSFS_ArchiveInfo ArchiveInfo; 46 | 47 | typedef std::vector ArchiveInfoList; 48 | 49 | typedef uint64 size_t; 50 | 51 | class base_fstream { 52 | protected: 53 | PHYSFS_File * const file; 54 | public: 55 | base_fstream(PHYSFS_File * file); 56 | virtual ~base_fstream(); 57 | size_t length(); 58 | }; 59 | 60 | class ifstream : public base_fstream, public std::istream { 61 | public: 62 | ifstream(string const & filename); 63 | virtual ~ifstream(); 64 | }; 65 | 66 | class ofstream : public base_fstream, public std::ostream { 67 | public: 68 | ofstream(string const & filename, mode writeMode = WRITE); 69 | virtual ~ofstream(); 70 | }; 71 | 72 | class fstream : public base_fstream, public std::iostream { 73 | public: 74 | fstream(string const & filename, mode openMode = READ); 75 | virtual ~fstream(); 76 | }; 77 | 78 | Version getLinkedVersion(); 79 | 80 | void init(char const * argv0); 81 | 82 | void deinit(); 83 | 84 | ArchiveInfoList supportedArchiveTypes(); 85 | 86 | string getDirSeparator(); 87 | 88 | void permitSymbolicLinks(bool allow); 89 | 90 | StringList getCdRomDirs(); 91 | 92 | void getCdRomDirs(StringCallback callback, void * extra); 93 | 94 | string getBaseDir(); 95 | 96 | string getUserDir(); 97 | 98 | string getWriteDir(); 99 | 100 | void setWriteDir(string const & newDir); 101 | 102 | void removeFromSearchPath(string const & oldDir); 103 | 104 | StringList getSearchPath(); 105 | 106 | void getSearchPath(StringCallback callback, void * extra); 107 | 108 | void setSaneConfig(string const & orgName, string const & appName, string const & archiveExt, bool includeCdRoms, bool archivesFirst); 109 | 110 | void mkdir(string const & dirName); 111 | 112 | void deleteFile(string const & filename); 113 | 114 | string getRealDir(string const & filename); 115 | 116 | StringList enumerateFiles(string const & directory); 117 | 118 | void enumerateFiles(string const & directory, EnumFilesCallback callback, void * extra); 119 | 120 | bool exists(string const & filename); 121 | 122 | bool isDirectory(string const & filename); 123 | 124 | bool isSymbolicLink(string const & filename); 125 | 126 | sint64 getLastModTime(string const & filename); 127 | 128 | bool isInit(); 129 | 130 | bool symbolicLinksPermitted(); 131 | 132 | void setAllocator(Allocator const * allocator); 133 | 134 | void mount(string const & newDir, string const & mountPoint, bool appendToPath); 135 | 136 | string getMountPoint(string const & dir); 137 | 138 | namespace Util { 139 | 140 | sint16 swapSLE16(sint16 value); 141 | 142 | uint16 swapULE16(uint16 value); 143 | 144 | sint32 swapSLE32(sint32 value); 145 | 146 | uint32 swapULE32(uint32 value); 147 | 148 | sint64 swapSLE64(sint64 value); 149 | 150 | uint64 swapULE64(uint64 value); 151 | 152 | sint16 swapSBE16(sint16 value); 153 | 154 | uint16 swapUBE16(uint16 value); 155 | 156 | sint32 swapSBE32(sint32 value); 157 | 158 | uint32 swapUBE32(uint32 value); 159 | 160 | sint64 swapSBE64(sint64 value); 161 | 162 | uint64 swapUBE64(uint64 value); 163 | 164 | string utf8FromUcs4(uint32 const * src); 165 | 166 | string utf8ToUcs4(char const * src); 167 | 168 | string utf8FromUcs2(uint16 const * src); 169 | 170 | string utf8ToUcs2(char const * src); 171 | 172 | string utf8FromLatin1(char const * src); 173 | 174 | } 175 | 176 | } 177 | 178 | #endif /* _INCLUDE_PHYSFS_HPP_ */ 179 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(physfs++ physfs.cpp) 2 | target_link_libraries(physfs++ physfs) 3 | -------------------------------------------------------------------------------- /src/physfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "physfs.hpp" 6 | 7 | using std::streambuf; 8 | using std::ios_base; 9 | 10 | namespace PhysFS { 11 | 12 | class fbuf : public streambuf { 13 | private: 14 | fbuf(const fbuf & other); 15 | fbuf& operator=(const fbuf& other); 16 | 17 | int_type underflow() { 18 | if (PHYSFS_eof(file)) { 19 | return traits_type::eof(); 20 | } 21 | size_t bytesRead = PHYSFS_read(file, buffer, 1, bufferSize); 22 | if (bytesRead < 1) { 23 | return traits_type::eof(); 24 | } 25 | setg(buffer, buffer, buffer + bytesRead); 26 | return (unsigned char) *gptr(); 27 | } 28 | 29 | pos_type seekoff(off_type pos, ios_base::seekdir dir, ios_base::openmode mode) { 30 | switch (dir) { 31 | case std::ios_base::beg: 32 | PHYSFS_seek(file, pos); 33 | break; 34 | case std::ios_base::cur: 35 | // subtract characters currently in buffer from seek position 36 | PHYSFS_seek(file, (PHYSFS_tell(file) + pos) - (egptr() - gptr())); 37 | break; 38 | case std::ios_base::end: 39 | PHYSFS_seek(file, PHYSFS_fileLength(file) + pos); 40 | break; 41 | } 42 | if (mode & std::ios_base::in) { 43 | setg(egptr(), egptr(), egptr()); 44 | } 45 | if (mode & std::ios_base::out) { 46 | setp(buffer, buffer); 47 | } 48 | return PHYSFS_tell(file); 49 | } 50 | 51 | pos_type seekpos(pos_type pos, std::ios_base::openmode mode) { 52 | PHYSFS_seek(file, pos); 53 | if (mode & std::ios_base::in) { 54 | setg(egptr(), egptr(), egptr()); 55 | } 56 | if (mode & std::ios_base::out) { 57 | setp(buffer, buffer); 58 | } 59 | return PHYSFS_tell(file); 60 | } 61 | 62 | int_type overflow( int_type c = traits_type::eof() ) { 63 | if (pptr() == pbase() && c == traits_type::eof()) { 64 | return 0; // no-op 65 | } 66 | if (PHYSFS_write(file, pbase(), pptr() - pbase(), 1) < 1) { 67 | return traits_type::eof(); 68 | } 69 | if (c != traits_type::eof()) { 70 | if (PHYSFS_write(file, &c, 1, 1) < 1) { 71 | return traits_type::eof(); 72 | } 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | int sync() { 79 | return overflow(); 80 | } 81 | 82 | char * buffer; 83 | size_t const bufferSize; 84 | protected: 85 | PHYSFS_File * const file; 86 | public: 87 | fbuf(PHYSFS_File * file, std::size_t bufferSize = 2048) : file(file), bufferSize(bufferSize) { 88 | buffer = new char[bufferSize]; 89 | char * end = buffer + bufferSize; 90 | setg(end, end, end); 91 | setp(buffer, end); 92 | } 93 | 94 | ~fbuf() { 95 | sync(); 96 | delete [] buffer; 97 | } 98 | }; 99 | 100 | base_fstream::base_fstream(PHYSFS_File* file) : file(file) { 101 | if (file == NULL) { 102 | throw std::invalid_argument("attempted to construct fstream with NULL ptr"); 103 | } 104 | } 105 | 106 | base_fstream::~base_fstream() { 107 | PHYSFS_close(file); 108 | } 109 | 110 | PhysFS::size_t base_fstream::length() { 111 | return PHYSFS_fileLength(file); 112 | } 113 | 114 | PHYSFS_File* openWithMode(char const * filename, mode openMode) { 115 | PHYSFS_File* file = NULL; 116 | switch (openMode) { 117 | case WRITE: 118 | file = PHYSFS_openWrite(filename); 119 | break; 120 | case APPEND: 121 | file = PHYSFS_openAppend(filename); 122 | break; 123 | case READ: 124 | file = PHYSFS_openRead(filename); 125 | } 126 | if (file == NULL) { 127 | throw std::invalid_argument("file not found: " + std::string(filename)); 128 | } 129 | return file; 130 | } 131 | 132 | ifstream::ifstream(const string& filename) 133 | : base_fstream(openWithMode(filename.c_str(), READ)), std::istream(new fbuf(file)) {} 134 | 135 | ifstream::~ifstream() { 136 | delete rdbuf(); 137 | } 138 | 139 | ofstream::ofstream(const string& filename, mode writeMode) 140 | : base_fstream(openWithMode(filename.c_str(), writeMode)), std::ostream(new fbuf(file)) {} 141 | 142 | ofstream::~ofstream() { 143 | delete rdbuf(); 144 | } 145 | 146 | fstream::fstream(const string& filename, mode openMode) 147 | : base_fstream(openWithMode(filename.c_str(), openMode)), std::iostream(new fbuf(file)) {} 148 | 149 | fstream::~fstream() { 150 | delete rdbuf(); 151 | } 152 | 153 | Version getLinkedVersion() { 154 | Version version; 155 | PHYSFS_getLinkedVersion(&version); 156 | return version; 157 | } 158 | 159 | void init(const char* argv0) { 160 | PHYSFS_init(argv0); 161 | } 162 | 163 | void deinit() { 164 | PHYSFS_deinit(); 165 | } 166 | 167 | ArchiveInfoList supportedArchiveTypes() { 168 | ArchiveInfoList list; 169 | for (const ArchiveInfo** archiveType = PHYSFS_supportedArchiveTypes(); *archiveType != NULL; archiveType++) { 170 | list.push_back(**archiveType); 171 | } 172 | return list; 173 | } 174 | 175 | string getDirSeparator() { 176 | return PHYSFS_getDirSeparator(); 177 | } 178 | 179 | void permitSymbolicLinks(bool allow) { 180 | PHYSFS_permitSymbolicLinks(allow); 181 | } 182 | 183 | StringList getCdRomDirs() { 184 | StringList dirs; 185 | char ** dirBegin = PHYSFS_getCdRomDirs(); 186 | for (char ** dir = dirBegin; *dir != NULL; dir++) { 187 | dirs.push_back(*dir); 188 | } 189 | PHYSFS_freeList(dirBegin); 190 | return dirs; 191 | } 192 | 193 | void getCdRomDirs(StringCallback callback, void * extra) { 194 | PHYSFS_getCdRomDirsCallback(callback, extra); 195 | } 196 | 197 | string getBaseDir() { 198 | return PHYSFS_getBaseDir(); 199 | } 200 | 201 | string getUserDir() { 202 | return PHYSFS_getUserDir(); 203 | } 204 | 205 | string getWriteDir() { 206 | return PHYSFS_getWriteDir(); 207 | } 208 | 209 | void setWriteDir(const string& newDir) { 210 | PHYSFS_setWriteDir(newDir.c_str()); 211 | } 212 | 213 | void removeFromSearchPath(const string& oldDir) { 214 | PHYSFS_removeFromSearchPath(oldDir.c_str()); 215 | } 216 | 217 | StringList getSearchPath() { 218 | StringList pathList; 219 | char ** pathBegin = PHYSFS_getSearchPath(); 220 | for (char ** path = pathBegin; *path != NULL; path++) { 221 | pathList.push_back(*path); 222 | } 223 | PHYSFS_freeList(pathBegin); 224 | return pathList; 225 | } 226 | 227 | void getSearchPath(StringCallback callback, void * extra) { 228 | PHYSFS_getSearchPathCallback(callback, extra); 229 | } 230 | 231 | void setSaneConfig(const string& orgName, const string& appName, 232 | const string& archiveExt, bool includeCdRoms, bool archivesFirst) { 233 | PHYSFS_setSaneConfig(orgName.c_str(), appName.c_str(), archiveExt.c_str(), includeCdRoms, archivesFirst); 234 | } 235 | 236 | void mkdir(const string& dirName) { 237 | PHYSFS_mkdir(dirName.c_str()); 238 | } 239 | 240 | void deleteFile(const string& filename) { 241 | PHYSFS_delete(filename.c_str()); 242 | } 243 | 244 | string getRealDir(const string& filename) { 245 | return PHYSFS_getRealDir(filename.c_str()); 246 | } 247 | 248 | StringList enumerateFiles(const string& directory) { 249 | StringList files; 250 | char ** listBegin = PHYSFS_enumerateFiles(directory.c_str()); 251 | for (char ** file = listBegin; *file != NULL; file++) { 252 | files.push_back(*file); 253 | } 254 | PHYSFS_freeList(listBegin); 255 | return files; 256 | } 257 | 258 | void enumerateFiles(const string& directory, EnumFilesCallback callback, void * extra) { 259 | PHYSFS_enumerateFilesCallback(directory.c_str(), callback, extra); 260 | } 261 | 262 | bool exists(const string& filename) { 263 | return PHYSFS_exists(filename.c_str()); 264 | } 265 | 266 | bool isDirectory(const string& filename) { 267 | return PHYSFS_isDirectory(filename.c_str()); 268 | } 269 | 270 | bool isSymbolicLink(const string& filename) { 271 | return PHYSFS_isSymbolicLink(filename.c_str()); 272 | } 273 | 274 | sint64 getLastModTime(const string& filename) { 275 | return PHYSFS_getLastModTime(filename.c_str()); 276 | } 277 | 278 | bool isInit() { 279 | return PHYSFS_isInit(); 280 | } 281 | 282 | bool symbolicLinksPermitted() { 283 | return PHYSFS_symbolicLinksPermitted(); 284 | } 285 | 286 | void setAllocator(const Allocator* allocator) { 287 | PHYSFS_setAllocator(allocator); 288 | } 289 | 290 | void mount(const string& newDir, const string& mountPoint, bool appendToPath) { 291 | PHYSFS_mount(newDir.c_str(), mountPoint.c_str(), appendToPath); 292 | } 293 | 294 | string getMountPoint(const string& dir) { 295 | return PHYSFS_getMountPoint(dir.c_str()); 296 | } 297 | 298 | sint16 Util::swapSLE16(sint16 value) { 299 | return PHYSFS_swapSLE16(value); 300 | } 301 | 302 | uint16 Util::swapULE16(uint16 value) { 303 | return PHYSFS_swapULE16(value); 304 | } 305 | 306 | sint32 Util::swapSLE32(sint32 value) { 307 | return PHYSFS_swapSLE32(value); 308 | } 309 | 310 | uint32 Util::swapULE32(uint32 value) { 311 | return PHYSFS_swapULE32(value); 312 | } 313 | 314 | sint64 Util::swapSLE64(sint64 value) { 315 | return PHYSFS_swapSLE64(value); 316 | } 317 | 318 | uint64 Util::swapULE64(uint64 value) { 319 | return PHYSFS_swapULE64(value); 320 | } 321 | 322 | sint16 Util::swapSBE16(sint16 value) { 323 | return PHYSFS_swapSBE16(value); 324 | } 325 | 326 | uint16 Util::swapUBE16(uint16 value) { 327 | return PHYSFS_swapUBE16(value); 328 | } 329 | 330 | sint32 Util::swapSBE32(sint32 value) { 331 | return PHYSFS_swapSBE32(value); 332 | } 333 | 334 | uint32 Util::swapUBE32(uint32 value) { 335 | return PHYSFS_swapUBE32(value); 336 | } 337 | 338 | sint64 Util::swapSBE64(sint64 value) { 339 | return PHYSFS_swapSBE64(value); 340 | } 341 | 342 | uint64 Util::swapUBE64(uint64 value) { 343 | return PHYSFS_swapUBE64(value); 344 | } 345 | 346 | string Util::utf8FromUcs4(const uint32* src) { 347 | string value; 348 | std::size_t length = strlen((char*) src); 349 | char * buffer = new char[length]; // will be smaller than len 350 | PHYSFS_utf8FromUcs4(src, buffer, length); 351 | value.append(buffer); 352 | return value; 353 | } 354 | 355 | string Util::utf8ToUcs4(const char* src) { 356 | string value; 357 | std::size_t length = strlen(src) * 4; 358 | char * buffer = new char[length]; // will be smaller than len 359 | PHYSFS_utf8ToUcs4(src, (uint32*) buffer, length); 360 | value.append(buffer); 361 | return value; 362 | } 363 | 364 | string Util::utf8FromUcs2(const uint16* src) { 365 | string value; 366 | std::size_t length = strlen((char*) src); 367 | char * buffer = new char[length]; // will be smaller than len 368 | PHYSFS_utf8FromUcs2(src, buffer, length); 369 | value.append(buffer); 370 | return value; 371 | } 372 | 373 | string Util::utf8ToUcs2(const char* src) { 374 | string value; 375 | std::size_t length = strlen(src) * 2; 376 | char * buffer = new char[length]; // will be smaller than len 377 | PHYSFS_utf8ToUcs2(src, (uint16*) buffer, length); 378 | value.append(buffer); 379 | return value; 380 | } 381 | 382 | string Util::utf8FromLatin1(const char* src) { 383 | string value; 384 | std::size_t length = strlen((char*) src) * 2; 385 | char * buffer = new char[length]; // will be smaller than len 386 | PHYSFS_utf8FromLatin1(src, buffer, length); 387 | value.append(buffer); 388 | return value; 389 | } 390 | 391 | } 392 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(physfs_test physfs_test.cpp) 2 | target_link_libraries(physfs_test physfs++ cppunit) 3 | add_test(physfs_test physfs_test) 4 | -------------------------------------------------------------------------------- /test/physfs_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class PhysfsTest : public CppUnit::TestFixture { 11 | CPPUNIT_TEST_SUITE(PhysfsTest); 12 | CPPUNIT_TEST(testExceptionThrownWhenFileNotFound); 13 | CPPUNIT_TEST_SUITE_END(); 14 | public: 15 | void testExceptionThrownWhenFileNotFound() { 16 | try { 17 | PhysFS::ifstream file("the_princess_is_in_another_castle"); 18 | CPPUNIT_ASSERT(false); // should not get here 19 | } catch (std::invalid_argument e) { 20 | } 21 | } 22 | }; 23 | 24 | 25 | int main(int argc, char** argv) { 26 | CppUnit::TextUi::TestRunner runner; 27 | runner.addTest(PhysfsTest::suite()); 28 | return runner.run() ? 0 : 1; 29 | } 30 | --------------------------------------------------------------------------------