diff options
author | Andrei Karas <akaras@inbox.ru> | 2017-02-21 17:08:42 +0300 |
---|---|---|
committer | Andrei Karas <akaras@inbox.ru> | 2017-02-21 17:16:24 +0300 |
commit | fc60e6391b53c7e272bbbfe81e34f64ceb92fe06 (patch) | |
tree | c2010fe985e24cd4e22346a29856a6fd003775bc /src/fs | |
parent | 01ac8bad77156f50ba57ddff5306714dc3815ef3 (diff) | |
download | manaverse-fc60e6391b53c7e272bbbfe81e34f64ceb92fe06.tar.gz manaverse-fc60e6391b53c7e272bbbfe81e34f64ceb92fe06.tar.bz2 manaverse-fc60e6391b53c7e272bbbfe81e34f64ceb92fe06.tar.xz manaverse-fc60e6391b53c7e272bbbfe81e34f64ceb92fe06.zip |
Move virt fs related files into fs directory.
Diffstat (limited to 'src/fs')
-rw-r--r-- | src/fs/virtfile.cpp | 37 | ||||
-rw-r--r-- | src/fs/virtfile.h | 39 | ||||
-rw-r--r-- | src/fs/virtfileprivate.cpp | 42 | ||||
-rw-r--r-- | src/fs/virtfileprivate.h | 44 | ||||
-rw-r--r-- | src/fs/virtfs.cpp | 304 | ||||
-rw-r--r-- | src/fs/virtfs.h | 79 | ||||
-rw-r--r-- | src/fs/virtfs_unittest.cc | 406 | ||||
-rw-r--r-- | src/fs/virtfsrwops.cpp | 434 | ||||
-rw-r--r-- | src/fs/virtfsrwops.h | 75 | ||||
-rw-r--r-- | src/fs/virtfstools.cpp | 223 | ||||
-rw-r--r-- | src/fs/virtfstools.h | 54 | ||||
-rw-r--r-- | src/fs/virtlist.cpp | 32 | ||||
-rw-r--r-- | src/fs/virtlist.h | 39 |
13 files changed, 1808 insertions, 0 deletions
diff --git a/src/fs/virtfile.cpp b/src/fs/virtfile.cpp new file mode 100644 index 000000000..9f9ab6e98 --- /dev/null +++ b/src/fs/virtfile.cpp @@ -0,0 +1,37 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "fs/virtfile.h" + +#include "fs/virtfileprivate.h" + +#include "utils/delete2.h" + +#include "debug.h" + +VirtFile::VirtFile() : + mPrivate(nullptr) +{ +} + +VirtFile::~VirtFile() +{ + delete2(mPrivate); +} diff --git a/src/fs/virtfile.h b/src/fs/virtfile.h new file mode 100644 index 000000000..cf7ded1a4 --- /dev/null +++ b/src/fs/virtfile.h @@ -0,0 +1,39 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_VIRTFILE_H +#define UTILS_VIRTFILE_H + +#include "localconsts.h" + +struct VirtFilePrivate; + +struct VirtFile final +{ + VirtFile(); + + A_DELETE_COPY(VirtFile) + + ~VirtFile(); + + VirtFilePrivate *mPrivate; +}; + +#endif // UTILS_VIRTFILE_H diff --git a/src/fs/virtfileprivate.cpp b/src/fs/virtfileprivate.cpp new file mode 100644 index 000000000..6bd5d3b9a --- /dev/null +++ b/src/fs/virtfileprivate.cpp @@ -0,0 +1,42 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "fs/virtfileprivate.h" + +#include "debug.h" + +VirtFilePrivate::VirtFilePrivate() : + mFile(nullptr) +{ +} + +VirtFilePrivate::VirtFilePrivate(PHYSFS_file *const file) : + mFile(file) +{ +} + +VirtFilePrivate::~VirtFilePrivate() +{ + if (mFile != nullptr) + { + PHYSFS_close(mFile); + mFile = nullptr; + } +} diff --git a/src/fs/virtfileprivate.h b/src/fs/virtfileprivate.h new file mode 100644 index 000000000..5b280de78 --- /dev/null +++ b/src/fs/virtfileprivate.h @@ -0,0 +1,44 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_VIRTFILEPRIVATE_H +#define UTILS_VIRTFILEPRIVATE_H + +#include "localconsts.h" + +PRAGMA45(GCC diagnostic push) +PRAGMA45(GCC diagnostic ignored "-Wlong-long") +#include <physfs.h> +PRAGMA45(GCC diagnostic pop) + +struct VirtFilePrivate final +{ + VirtFilePrivate(); + + explicit VirtFilePrivate(PHYSFS_file *const file); + + A_DELETE_COPY(VirtFilePrivate) + + ~VirtFilePrivate(); + + PHYSFS_file *mFile; +}; + +#endif // UTILS_VIRTFILEPRIVATE_H diff --git a/src/fs/virtfs.cpp b/src/fs/virtfs.cpp new file mode 100644 index 000000000..0db25f435 --- /dev/null +++ b/src/fs/virtfs.cpp @@ -0,0 +1,304 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "fs/virtfs.h" + +#include "fs/virtfile.h" +#include "fs/virtfileprivate.h" +#include "fs/virtlist.h" + +#include "utils/checkutils.h" + +#include <iostream> +#include <unistd.h> + +#ifdef ANDROID +#include "utils/paths.h" +#endif // ANDROID + +#include "debug.h" + +const char *dirSeparator = nullptr; + +namespace VirtFs +{ +#if defined(__native_client__) + void init(const std::string &restrict name A_UNUSED) + { + if (!PHYSFS_init("/fakebinary")) +#elif defined(ANDROID) + void init(const std::string &restrict name A_UNUSED) + { + if (!PHYSFS_init((getRealPath(".").append("/fakebinary")).c_str())) +#else // defined(__native_client__) + + void init(const std::string &restrict name) + { + if (!PHYSFS_init(name.c_str())) +#endif // defined(__native_client__) + { + std::cout << "Error while initializing PhysFS: " + << VirtFs::getLastError() << std::endl; + _exit(1); + } + updateDirSeparator(); + atexit(reinterpret_cast<void(*)()>(PHYSFS_deinit)); + } + + void updateDirSeparator() + { + dirSeparator = PHYSFS_getDirSeparator(); + } + + const char *getDirSeparator() + { + return dirSeparator; + } + + const char *getBaseDir() + { + return PHYSFS_getBaseDir(); + } + + const char *getUserDir() + { + return PHYSFS_getUserDir(); + } + + bool exists(const std::string &restrict name) + { + return PHYSFS_exists(name.c_str()); + } + + VirtList *enumerateFiles(const std::string &restrict dir) + { + char ** handle = PHYSFS_enumerateFiles(dir.c_str()); + VirtList *const files = new VirtList; + if (handle == nullptr) + return files; + for (const char *const *i = handle; *i; i++) + { + std::string str = *i; + files->names.push_back(str); + } + PHYSFS_freeList(handle); + return files; + } + + bool isDirectory(const std::string &restrict name) + { + return PHYSFS_isDirectory(name.c_str()); + } + + bool isSymbolicLink(const std::string &restrict name) + { + return PHYSFS_isSymbolicLink(name.c_str()); + } + + void freeList(VirtList *restrict const handle) + { + delete handle; + } + + VirtFile *openRead(const std::string &restrict filename) + { + PHYSFS_file *restrict const handle = PHYSFS_openRead( + filename.c_str()); + if (!handle) + return nullptr; + VirtFile *restrict const file = new VirtFile; + file->mPrivate = new VirtFilePrivate(handle); + return file; + } + + VirtFile *openWrite(const std::string &restrict filename) + { + PHYSFS_file *restrict const handle = PHYSFS_openWrite( + filename.c_str()); + if (!handle) + return nullptr; + VirtFile *restrict const file = new VirtFile; + file->mPrivate = new VirtFilePrivate(handle); + return file; + } + + VirtFile *openAppend(const std::string &restrict filename) + { + PHYSFS_file *restrict const handle = PHYSFS_openAppend( + filename.c_str()); + if (!handle) + return nullptr; + VirtFile *restrict const file = new VirtFile; + file->mPrivate = new VirtFilePrivate(handle); + return file; + } + + bool setWriteDir(const std::string &restrict newDir) + { + return PHYSFS_setWriteDir(newDir.c_str()); + } + + bool addDirToSearchPath(const std::string &restrict newDir, + const Append append) + { + logger->log("Add virtual directory: " + newDir); + if (newDir.find(".zip") != std::string::npos) + { + reportAlways("Called addDirToSearchPath with zip archive"); + return false; + } + return PHYSFS_addToSearchPath(newDir.c_str(), + append == Append_true ? 1 : 0); + } + + bool removeDirFromSearchPath(const std::string &restrict oldDir) + { + logger->log("Remove virtual directory: " + oldDir); + if (oldDir.find(".zip") != std::string::npos) + { + reportAlways("Called removeDirFromSearchPath with zip archive"); + return false; + } + return PHYSFS_removeFromSearchPath(oldDir.c_str()); + } + + bool addZipToSearchPath(const std::string &restrict newDir, + const Append append) + { + logger->log("Add virtual zip: " + newDir); + if (newDir.find(".zip") == std::string::npos) + { + reportAlways("Called addZipToSearchPath without zip archive"); + return false; + } + return PHYSFS_addToSearchPath(newDir.c_str(), + append == Append_true ? 1 : 0); + } + + bool removeZipFromSearchPath(const std::string &restrict oldDir) + { + logger->log("Remove virtual zip: " + oldDir); + if (oldDir.find(".zip") == std::string::npos) + { + reportAlways("Called removeZipFromSearchPath without zip archive"); + return false; + } + return PHYSFS_removeFromSearchPath(oldDir.c_str()); + } + + std::string getRealDir(const std::string &restrict filename) + { + const char *const str = PHYSFS_getRealDir(filename.c_str()); + if (str == nullptr) + return std::string(); + return str; + } + + bool mkdir(const std::string &restrict dirname) + { + return PHYSFS_mkdir(dirname.c_str()); + } + + bool remove(const std::string &restrict filename) + { + return PHYSFS_delete(filename.c_str()); + } + + bool deinit() + { + if (PHYSFS_deinit() != 0) + { + logger->log("Physfs deinit error: %s", + VirtFs::getLastError()); + return false; + } + return true; + } + + void permitLinks(const bool val) + { + PHYSFS_permitSymbolicLinks(val ? 1 : 0); + } + + const char *getLastError() + { + return PHYSFS_getLastError(); + } + + int close(VirtFile *restrict const file) + { + if (file == nullptr) + return 0; + delete file; + return 1; + } + + int64_t read(VirtFile *restrict const file, + void *restrict const buffer, + const uint32_t objSize, + const uint32_t objCount) + { + if (file == nullptr) + return 0; + return PHYSFS_read(file->mPrivate->mFile, + buffer, + objSize, + objCount); + } + + int64_t write(VirtFile *restrict const file, + const void *restrict const buffer, + const uint32_t objSize, + const uint32_t objCount) + { + if (file == nullptr) + return 0; + return PHYSFS_write(file->mPrivate->mFile, + buffer, + objSize, + objCount); + } + + int64_t fileLength(VirtFile *restrict const file) + { + if (file == nullptr) + return -1; + return PHYSFS_fileLength(file->mPrivate->mFile); + } + + int64_t tell(VirtFile *restrict const file) + { + if (file == nullptr) + return -1; + return PHYSFS_tell(file->mPrivate->mFile); + } + + int seek(VirtFile *restrict const file, + const uint64_t pos) + { + return PHYSFS_seek(file->mPrivate->mFile, + pos); + } + + int eof(VirtFile *restrict const file) + { + return PHYSFS_eof(file->mPrivate->mFile); + } +} // namespace VirtFs diff --git a/src/fs/virtfs.h b/src/fs/virtfs.h new file mode 100644 index 000000000..e0f188cfb --- /dev/null +++ b/src/fs/virtfs.h @@ -0,0 +1,79 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_VIRTFS_H +#define UTILS_VIRTFS_H + +#include "enums/simpletypes/append.h" + +#include "localconsts.h" + +#include <string> + +struct VirtFile; +struct VirtList; + +namespace VirtFs +{ + void init(const std::string &restrict name); + void updateDirSeparator(); + const char *getDirSeparator(); + const char *getBaseDir(); + const char *getUserDir(); + bool exists(const std::string &restrict name); + VirtList *enumerateFiles(const std::string &restrict dir) RETURNS_NONNULL; + bool isDirectory(const std::string &restrict name); + bool isSymbolicLink(const std::string &restrict name); + void freeList(VirtList *restrict const handle); + VirtFile *openRead(const std::string &restrict filename); + VirtFile *openWrite(const std::string &restrict filename); + VirtFile *openAppend(const std::string &restrict filename); + bool setWriteDir(const std::string &restrict newDir); + bool addDirToSearchPath(const std::string &restrict newDir, + const Append append); + bool removeDirFromSearchPath(const std::string &restrict oldDir); + bool addZipToSearchPath(const std::string &restrict newDir, + const Append append); + bool removeZipFromSearchPath(const std::string &restrict oldDir); + std::string getRealDir(const std::string &restrict filename); + bool mkdir(const std::string &restrict dirName); + bool remove(const std::string &restrict filename); + bool deinit(); + void permitLinks(const bool val); + const char *getLastError(); + int64_t read(VirtFile *restrict const handle, + void *restrict const buffer, + const uint32_t objSize, + const uint32_t objCount); + int64_t write(VirtFile *restrict const file, + const void *restrict const buffer, + const uint32_t objSize, + const uint32_t objCount); + int close(VirtFile *restrict const file); + int64_t fileLength(VirtFile *restrict const file); + int64_t tell(VirtFile *restrict const file); + int seek(VirtFile *restrict const file, + const uint64_t pos); + int eof(VirtFile *restrict const file); +} // namespace VirtFs + +extern const char *dirSeparator; + +#endif // UTILS_VIRTFS_H diff --git a/src/fs/virtfs_unittest.cc b/src/fs/virtfs_unittest.cc new file mode 100644 index 000000000..4f3a74a7b --- /dev/null +++ b/src/fs/virtfs_unittest.cc @@ -0,0 +1,406 @@ +/* + * The ManaPlus Client + * Copyright (C) 2016-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "catch.hpp" + +#include "fs/virtfs.h" +#include "fs/virtfstools.h" +#include "fs/virtlist.h" + +#include "utils/checkutils.h" +#include "utils/delete2.h" + +#include "debug.h" + +TEST_CASE("VirtFs dirSeparator") +{ + REQUIRE(dirSeparator != nullptr); + REQUIRE(VirtFs::getDirSeparator() == std::string(dirSeparator)); + VirtFs::updateDirSeparator(); + REQUIRE(dirSeparator != nullptr); + REQUIRE(VirtFs::getDirSeparator() == std::string(dirSeparator)); +} + +TEST_CASE("VirtFs getBaseDir") +{ + REQUIRE(VirtFs::getBaseDir() != nullptr); +} + +TEST_CASE("VirtFs getUserDir") +{ + REQUIRE(VirtFs::getUserDir() != nullptr); +} + +TEST_CASE("VirtFs exists") +{ + logger = new Logger(); + VirtFs::addDirToSearchPath("data", Append_false); + VirtFs::addDirToSearchPath("../data", Append_false); + + REQUIRE(VirtFs::exists("test/units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == false); + + VirtFs::addDirToSearchPath("data/test", Append_false); + VirtFs::addDirToSearchPath("../data/test", Append_false); + + REQUIRE(VirtFs::exists("test/units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == true); + + VirtFs::removeDirFromSearchPath("data/test"); + VirtFs::removeDirFromSearchPath("../data/test"); + + REQUIRE(VirtFs::exists("test/units.xml") == true); + REQUIRE(VirtFs::exists("test/units123.xml") == false); + REQUIRE(VirtFs::exists("tesQ/units.xml") == false); + REQUIRE(VirtFs::exists("units.xml") == false); + + VirtFs::removeDirFromSearchPath("data"); + VirtFs::removeDirFromSearchPath("../data"); + delete2(logger); +} + +static void removeTemp(StringVect &restrict list) +{ + int cnt = 0; + std::sort(list.begin(), list.end()); + + FOR_EACH (StringVectIter, it, list) + { + if (*it != "serverlistplus.xml.part") + { + logger->log("file: %d %s", + cnt, + (*it).c_str()); + cnt ++; + } + } + + FOR_EACH (StringVectIter, it, list) + { + if (*it == "serverlistplus.xml.part") + { + list.erase(it); + return; + } + } +} + +TEST_CASE("VirtFs enumerateFiles") +{ + logger = new Logger; + + VirtFs::addDirToSearchPath("data", Append_false); + VirtFs::addDirToSearchPath("../data", Append_false); + + VirtList *list = nullptr; + + const int cnt1 = VirtFs::exists("test/test2.txt") ? 23 : 22; + const int cnt2 = 23; + + VirtFs::permitLinks(false); + list = VirtFs::enumerateFiles("test"); + removeTemp(list->names); + const size_t sz = list->names.size(); + REQUIRE(sz == cnt1); + VirtFs::freeList(list); + + VirtFs::permitLinks(true); + list = VirtFs::enumerateFiles("test"); + removeTemp(list->names); + REQUIRE(list->names.size() == cnt2); + VirtFs::freeList(list); + + VirtFs::permitLinks(false); + list = VirtFs::enumerateFiles("test"); + removeTemp(list->names); + REQUIRE(list->names.size() == cnt1); + VirtFs::freeList(list); + + VirtFs::removeDirFromSearchPath("data"); + VirtFs::removeDirFromSearchPath("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs isDirectory") +{ + logger = new Logger(); + VirtFs::addDirToSearchPath("data", Append_false); + VirtFs::addDirToSearchPath("../data", Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test//units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("test//units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ//units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("test/") == true); + REQUIRE(VirtFs::isDirectory("test//") == true); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + REQUIRE(VirtFs::isDirectory("test//dir1") == true); + REQUIRE(VirtFs::isDirectory("test//dir1/") == true); + REQUIRE(VirtFs::isDirectory("test//dir1//") == true); + REQUIRE(VirtFs::isDirectory("test/dir1/") == true); + REQUIRE(VirtFs::isDirectory("test/dir1//") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("testQ/") == false); + REQUIRE(VirtFs::isDirectory("testQ//") == false); + + VirtFs::addDirToSearchPath("data/test", Append_false); + VirtFs::addDirToSearchPath("../data/test", Append_false); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test//units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + + VirtFs::removeDirFromSearchPath("data/test"); + VirtFs::removeDirFromSearchPath("../data/test"); + + REQUIRE(VirtFs::isDirectory("test/units.xml") == false); + REQUIRE(VirtFs::isDirectory("test/units123.xml") == false); + REQUIRE(VirtFs::isDirectory("tesQ/units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml") == false); + REQUIRE(VirtFs::isDirectory("units.xml/") == false); + REQUIRE(VirtFs::isDirectory("test") == true); + REQUIRE(VirtFs::isDirectory("test/") == true); + REQUIRE(VirtFs::isDirectory("testQ") == false); + REQUIRE(VirtFs::isDirectory("test/dir1") == true); + + VirtFs::removeDirFromSearchPath("data"); + VirtFs::removeDirFromSearchPath("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs openRead") +{ + logger = new Logger(); + VirtFs::addDirToSearchPath("data", Append_false); + VirtFs::addDirToSearchPath("../data", Append_false); + + VirtFile *file = nullptr; + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file == nullptr); +// file = VirtFs::openRead("test"); +// REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::addDirToSearchPath("data/test", Append_false); + VirtFs::addDirToSearchPath("../data/test", Append_false); + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); +// file = VirtFs::openRead("test"); +// REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::removeDirFromSearchPath("data/test"); + VirtFs::removeDirFromSearchPath("../data/test"); + + file = VirtFs::openRead("test/units.xml"); + REQUIRE(file != nullptr); + VirtFs::close(file); + file = VirtFs::openRead("test/units123.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("tesQ/units.xml"); + REQUIRE(file == nullptr); + file = VirtFs::openRead("units.xml"); + REQUIRE(file == nullptr); +// file = VirtFs::openRead("test"); +// REQUIRE(file == nullptr); + file = VirtFs::openRead("testQ"); + REQUIRE(file == nullptr); + + VirtFs::removeDirFromSearchPath("data"); + VirtFs::removeDirFromSearchPath("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs addZipToSearchPath") +{ + // +++ need implement +} + +TEST_CASE("VirtFs removeZipFromSearchPath") +{ + // +++ need implement +} + +TEST_CASE("VirtFs getRealDir") +{ + logger = new Logger(); + REQUIRE(VirtFs::getRealDir(".") == ""); + REQUIRE(VirtFs::getRealDir("..") == ""); + const bool dir1 = VirtFs::addDirToSearchPath("data", Append_false); + REQUIRE((dir1 || VirtFs::addDirToSearchPath("../data", Append_false)) == + true); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == "../data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "../data"); + } + REQUIRE(VirtFs::getRealDir("zzz") == ""); + + VirtFs::addDirToSearchPath("data/test", Append_false); + VirtFs::addDirToSearchPath("../data/test", Append_false); + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + REQUIRE(VirtFs::getRealDir("test.txt") == + "data/test"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == "../data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "../data"); + REQUIRE(VirtFs::getRealDir("test.txt") == + "../data/test"); + } + REQUIRE(VirtFs::getRealDir("zzz") == ""); + + VirtFs::removeDirFromSearchPath("data/test"); + VirtFs::removeDirFromSearchPath("../data/test"); + + if (dir1 == true) + { + REQUIRE(VirtFs::getRealDir("test") == "data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "data"); + } + else + { + REQUIRE(VirtFs::getRealDir("test") == "../data"); + REQUIRE(VirtFs::getRealDir("test/test.txt") == + "../data"); + } + REQUIRE(VirtFs::getRealDir("zzz") == ""); + + VirtFs::removeDirFromSearchPath("data"); + VirtFs::removeDirFromSearchPath("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs permitLinks") +{ + logger = new Logger(); + VirtFs::addDirToSearchPath("data", Append_false); + VirtFs::addDirToSearchPath("../data", Append_false); + + const int cnt1 = VirtFs::exists("test/test2.txt") ? 22 : 21; + const int cnt2 = 22; + + StringVect list; + VirtFs::permitLinks(false); + VirtFs::getFiles("test", list); + removeTemp(list); + const size_t sz = list.size(); + REQUIRE(sz == cnt1); + + list.clear(); + VirtFs::permitLinks(true); + VirtFs::getFiles("test", list); + removeTemp(list); + REQUIRE(list.size() == cnt2); + + list.clear(); + VirtFs::permitLinks(false); + VirtFs::getFiles("test", list); + removeTemp(list); + REQUIRE(list.size() == cnt1); + + VirtFs::removeDirFromSearchPath("data"); + VirtFs::removeDirFromSearchPath("../data"); + delete2(logger); +} + +TEST_CASE("VirtFs read") +{ + logger = new Logger(); + VirtFs::addDirToSearchPath("data", Append_false); + VirtFs::addDirToSearchPath("../data", Append_false); + + VirtFile *file = VirtFs::openRead("test/test.txt"); + REQUIRE(file != nullptr); + REQUIRE(VirtFs::fileLength(file) == 23); + const int fileSize = VirtFs::fileLength(file); + + void *restrict buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::read(file, buffer, 1, fileSize) == fileSize); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 1\ntest line 2") == 0); + REQUIRE(VirtFs::tell(file) == fileSize); + REQUIRE(VirtFs::eof(file) == true); + + free(buffer); + buffer = calloc(fileSize + 1, 1); + REQUIRE(VirtFs::seek(file, 12) != 0); + REQUIRE(VirtFs::eof(file) == false); + REQUIRE(VirtFs::tell(file) == 12); + REQUIRE(VirtFs::read(file, buffer, 1, 11) == 11); + REQUIRE(strcmp(static_cast<char*>(buffer), + "test line 2") == 0); + REQUIRE(VirtFs::eof(file) == true); + + VirtFs::close(file); + free(buffer); + + VirtFs::removeDirFromSearchPath("data"); + VirtFs::removeDirFromSearchPath("../data"); + delete2(logger); +} diff --git a/src/fs/virtfsrwops.cpp b/src/fs/virtfsrwops.cpp new file mode 100644 index 000000000..036d8bb60 --- /dev/null +++ b/src/fs/virtfsrwops.cpp @@ -0,0 +1,434 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@icculus.org). + * + * Copyright (C) 2012-2017 The ManaPlus Developers + */ + +#include "fs/virtfsrwops.h" + +#include "logger.h" + +#include "fs/virtfs.h" + +#ifdef DEBUG_VIRTFS +#include "utils/debugmemoryobject.h" + +#include <map> +#endif // DEBUG_VIRTFS + +#include "utils/fuzzer.h" + +#include "debug.h" + +#ifdef USE_SDL2 +#define RWOPSINT int64_t +#define RWOPSSIZE size_t +#else // USE_SDL2 +#define RWOPSINT int32_t +#define RWOPSSIZE int +#endif // USE_SDL2 + +#ifdef DUMP_LEAKED_RESOURCES +static int openedRWops = 0; +#endif // DUMP_LEAKED_RESOURCES + +#ifdef DEBUG_VIRTFS +namespace +{ + std::map<void*, VirtFs::DebugMemoryObject*> mRWops; +} // namespace + +static SDL_RWops *addDebugRWops(SDL_RWops *restrict const rwops, + const char *restrict const name, + const char *restrict const file, + const unsigned line) +{ + if (!rwops) + return nullptr; + + mRWops[rwops] = new VirtFs::DebugMemoryObject(name, file, line); + return rwops; +} + +static void deleteDebugRWops(SDL_RWops *const rwops) +{ + if (!rwops) + return; + + std::map<void*, VirtFs::DebugMemoryObject*>::iterator it = + mRWops.find(rwops); + if (it == mRWops.end()) + { + logger->log("bad RWops delete: %p", static_cast<void*>(rwops)); + } + else + { + VirtFs::DebugMemoryObject *const obj = (*it).second; + if (obj) + { + mRWops.erase(rwops); + delete obj; + } + } +} + +void VirtFs::reportLeaks() +{ + if (!mRWops.empty()) + { + logger->log("RWops leaks detected"); + std::map<void*, VirtFs::DebugMemoryObject*>::iterator it = + mRWops.begin(); + const std::map<void*, VirtFs::DebugMemoryObject*>::iterator + it_end = mRWops.end(); + for (; it != it_end; ++it) + { + VirtFs::DebugMemoryObject *obj = (*it).second; + if (obj) + { + logger->log("file: %s at %s", obj->mName.c_str(), + obj->mAddFile.c_str()); + delete obj; + } + } + mRWops.clear(); + } +} +#endif // DEBUG_VIRTFS + +static RWOPSINT virtfsrwops_seek(SDL_RWops *const rw, + const RWOPSINT offset, + const int whence) +{ + if (!rw) + return -1; + VirtFile *const handle = static_cast<VirtFile *const>( + rw->hidden.unknown.data1); + RWOPSINT pos = 0; + + if (whence == SEEK_SET) + { + pos = offset; + } /* if */ + else if (whence == SEEK_CUR) + { + const int64_t current = VirtFs::tell(handle); + if (current == -1) + { + logger->assertLog( + "virtfsrwops_seek: Can't find position in file: %s", + VirtFs::getLastError()); + return -1; + } /* if */ + + pos = CAST_S32(current); + if (static_cast<int64_t>(pos) != current) + { + logger->assertLog("virtfsrwops_seek: " + "Can't fit current file position in an int!"); + return -1; + } /* if */ + + if (offset == 0) /* this is a "tell" call. We're done. */ + return pos; + + pos += offset; + } /* else if */ + else if (whence == SEEK_END) + { + const int64_t len = VirtFs::fileLength(handle); + if (len == -1) + { + logger->assertLog("virtfsrwops_seek:Can't find end of file: %s", + VirtFs::getLastError()); + return -1; + } /* if */ + + pos = static_cast<RWOPSINT>(len); + if (static_cast<int64_t>(pos) != len) + { + logger->assertLog("virtfsrwops_seek: " + "Can't fit end-of-file position in an int!"); + return -1; + } /* if */ + + pos += offset; + } /* else if */ + else + { + logger->assertLog("virtfsrwops_seek: Invalid 'whence' parameter."); + return -1; + } /* else */ + + if (pos < 0) + { + logger->assertLog("virtfsrwops_seek: " + "Attempt to seek past start of file."); + return -1; + } /* if */ + + if (!VirtFs::seek(handle, static_cast<uint64_t>(pos))) + { + logger->assertLog("virtfsrwops_seek: seek error: %s", + VirtFs::getLastError()); + return -1; + } /* if */ + + return pos; +} /* virtfsrwops_seek */ + +static RWOPSSIZE virtfsrwops_read(SDL_RWops *const rw, + void *const ptr, + const RWOPSSIZE size, + const RWOPSSIZE maxnum) +{ + if (!rw) + return 0; + VirtFile *const handle = static_cast<VirtFile *const>( + rw->hidden.unknown.data1); + const int64_t rc = VirtFs::read(handle, ptr, + CAST_U32(size), + CAST_U32(maxnum)); + if (rc != static_cast<int64_t>(maxnum)) + { + if (!VirtFs::eof(handle)) /* not EOF? Must be an error. */ + { + logger->assertLog("virtfsrwops_seek: read error: %s", + VirtFs::getLastError()); + } + } /* if */ + + return CAST_S32(rc); +} /* virtfsrwops_read */ + +static RWOPSSIZE virtfsrwops_write(SDL_RWops *const rw, + const void *const ptr, + const RWOPSSIZE size, + const RWOPSSIZE num) +{ + if (!rw) + return 0; + VirtFile *const handle = static_cast<VirtFile *const>( + rw->hidden.unknown.data1); + const int64_t rc = VirtFs::write(handle, ptr, + CAST_U32(size), + CAST_U32(num)); + if (rc != static_cast<int64_t>(num)) + { + logger->assertLog("virtfsrwops_seek: write error: %s", + VirtFs::getLastError()); + } + + return CAST_S32(rc); +} /* virtfsrwops_write */ + +static int virtfsrwops_close(SDL_RWops *const rw) +{ + if (!rw) + return 0; + VirtFile *const handle = static_cast<VirtFile*>( + rw->hidden.unknown.data1); + if (!VirtFs::close(handle)) + { + logger->assertLog("virtfsrwops_seek: close error: %s", + VirtFs::getLastError()); + return -1; + } /* if */ + + SDL_FreeRW(rw); +#ifdef DUMP_LEAKED_RESOURCES + if (openedRWops <= 0) + logger->assertLog("virtfsrwops_seek: closing already closed RWops"); + openedRWops --; +#endif // DUMP_LEAKED_RESOURCES +#ifdef DEBUG_VIRTFS + deleteDebugRWops(rw); +#endif // DEBUG_VIRTFS + + return 0; +} /* virtfsrwops_close */ + +#ifdef USE_SDL2 +static RWOPSINT virtfsrwops_size(SDL_RWops *const rw) +{ + VirtFile *const handle = static_cast<VirtFile *const>( + rw->hidden.unknown.data1); + return VirtFs::fileLength(handle); +} /* virtfsrwops_size */ +#endif // USE_SDL2 + +static SDL_RWops *create_rwops(VirtFile *const file) +{ + SDL_RWops *retval = nullptr; + + if (!file) + { + logger->assertLog("virtfsrwops_seek: create rwops error: %s", + VirtFs::getLastError()); + } + else + { + retval = SDL_AllocRW(); + if (retval) + { +#ifdef USE_SDL2 + retval->size = &virtfsrwops_size; +#endif // USE_SDL2 + + retval->seek = &virtfsrwops_seek; + retval->read = &virtfsrwops_read; + retval->write = &virtfsrwops_write; + retval->close = &virtfsrwops_close; + retval->hidden.unknown.data1 = file; + } /* if */ +#ifdef DUMP_LEAKED_RESOURCES + openedRWops ++; +#endif // DUMP_LEAKED_RESOURCES + } /* else */ + + return retval; +} /* create_rwops */ + +SDL_RWops *VirtFs::MakeRWops(VirtFile *const handle) +{ + SDL_RWops *retval = nullptr; + if (!handle) + { + logger->assertLog("virtfsrwops_seek: NULL pointer passed to " + "RWopsmakeRWops()."); + } + else + { + retval = create_rwops(handle); + } + + return retval; +} /* RWopsmakeRWops */ + +#ifdef __APPLE__ +static bool checkFilePath(const std::string &restrict fname) +{ + if (fname.empty()) + return false; + if (!VirtFs::exists(fname) || VirtFs::isDirectory(fname)) + return false; + return true; +} +#endif // __APPLE__ + +#ifdef DEBUG_VIRTFS +#undef RWopsOpenRead +SDL_RWops *VirtFs::RWopsOpenRead(const std::string &restrict fname, + const char *restrict const file, + const unsigned line) +#else // DEBUG_VIRTFS +SDL_RWops *VirtFs::RWopsOpenRead(const std::string &restrict fname) +#endif // DEBUG_VIRTFS +{ + BLOCK_START("RWopsopenRead") +#ifdef __APPLE__ + if (!checkFilePath(fname)) + return nullptr; +#endif // __APPLE__ +#ifdef USE_FUZZER + if (Fuzzer::conditionTerminate(fname)) + return nullptr; +#endif // USE_FUZZER +#ifdef USE_PROFILER + +#ifdef DEBUG_VIRTFS + SDL_RWops *const ret = addDebugRWops( + create_rwops(VirtFs::openRead(fname)), + fname, + file, + line); +#else // DEBUG_VIRTFS + SDL_RWops *const ret = create_rwops(VirtFs::openRead(fname)); +#endif // DEBUG_VIRTFS + + BLOCK_END("RWopsopenRead") + return ret; +#else // USE_PROFILER + +#ifdef DEBUG_VIRTFS + return addDebugRWops( + create_rwops(VirtFs::openRead(fname)), + fname, + file, + line); +#else // DEBUG_VIRTFS + return create_rwops(VirtFs::openRead(fname)); +#endif // DEBUG_VIRTFS +#endif // USE_PROFILER +} /* RWopsopenRead */ + +SDL_RWops *VirtFs::RWopsOpenWrite(const std::string &restrict fname) +{ +#ifdef __APPLE__ + if (!checkFilePath(fname)) + return nullptr; +#endif // __APPLE__ + + return create_rwops(VirtFs::openWrite(fname)); +} /* RWopsopenWrite */ + +SDL_RWops *VirtFs::RWopsOpenAppend(const std::string &restrict fname) +{ +#ifdef __APPLE__ + if (!checkFilePath(fname)) + return nullptr; +#endif // __APPLE__ + + return create_rwops(VirtFs::openAppend(fname)); +} /* RWopsopenAppend */ + +#ifdef DUMP_LEAKED_RESOURCES +void VirtFs::reportRWops() +{ + if (openedRWops) + { + logger->assertLog("virtfsrwops_seek: leaking RWops: %d", + openedRWops); + } +} +#endif // DUMP_LEAKED_RESOURCES + +/* end of physfsrwops.c ... */ diff --git a/src/fs/virtfsrwops.h b/src/fs/virtfsrwops.h new file mode 100644 index 000000000..82bb740de --- /dev/null +++ b/src/fs/virtfsrwops.h @@ -0,0 +1,75 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This code provides a glue layer between PhysicsFS and Simple Directmedia + * Layer's (SDL) RWops i/o abstraction. + * + * License: this code is public domain. I make no warranty that it is useful, + * correct, harmless, or environmentally safe. + * + * This particular file may be used however you like, including copying it + * verbatim into a closed-source project, exploiting it commercially, and + * removing any trace of my name from the source (although I hope you won't + * do that). I welcome enhancements and corrections to this file, but I do + * not require you to send me patches if you make changes. This code has + * NO WARRANTY. + * + * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license. + * Please see LICENSE.txt in the root of the source tree. + * + * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/ + * + * This file was written by Ryan C. Gordon. (icculus@icculus.org). + * + * Copyright (C) 2012-2017 The ManaPlus Developers + */ + +#ifndef UTILS_PHYSFSRWOPS_H +#define UTILS_PHYSFSRWOPS_H + +#include "localconsts.h" + +#include <string> +#include <SDL_rwops.h> + +struct VirtFile; + +namespace VirtFs +{ +#ifdef DEBUG_VIRTFS + SDL_RWops *RWopsOpenRead(const std::string &restrict fname, + const char *restrict const file, + const unsigned line); + void reportLeaks(); +#else // DEBUG_VIRTFS + SDL_RWops *RWopsOpenRead(const std::string &restrict fname); +#endif // DEBUG_VIRTFS + + SDL_RWops *RWopsOpenWrite(const std::string &restrict fname) A_WARN_UNUSED; + SDL_RWops *RWopsOpenAppend(const std::string &restrict fname) + A_WARN_UNUSED; + SDL_RWops *MakeRWops(VirtFile *const handle) A_WARN_UNUSED; +#ifdef DUMP_LEAKED_RESOURCES + void reportRWops(); +#endif // DUMP_LEAKED_RESOURCES +} // namespace VirtFs + +#endif // UTILS_PHYSFSRWOPS_H diff --git a/src/fs/virtfstools.cpp b/src/fs/virtfstools.cpp new file mode 100644 index 000000000..4d6c96c33 --- /dev/null +++ b/src/fs/virtfstools.cpp @@ -0,0 +1,223 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "fs/virtfstools.h" + +#include "logger.h" + +#include "fs/virtfs.h" +#include "fs/virtlist.h" + +#include "utils/paths.h" +#include "utils/stringutils.h" + +#include <algorithm> +#include <sstream> + +#include "debug.h" + +namespace VirtFs +{ + void *loadFile(const std::string &restrict fileName, + int &restrict fileSize) + { + // Attempt to open the specified file using PhysicsFS + VirtFile *restrict const file = VirtFs::openRead(fileName); + + if (!file) + { + logger->log("Warning: Failed to load %s: %s", + fileName.c_str(), + VirtFs::getLastError()); + return nullptr; + } + + logger->log("Loaded %s/%s", + VirtFs::getRealDir(fileName).c_str(), + fileName.c_str()); + + fileSize = CAST_S32(VirtFs::fileLength(file)); + // Allocate memory and load the file + void *restrict const buffer = calloc(fileSize, 1); + VirtFs::read(file, buffer, 1, fileSize); + VirtFs::close(file); + + return buffer; + } + + void searchAndAddArchives(const std::string &restrict path, + const std::string &restrict ext, + const Append append) + { + VirtList *const list = VirtFs::enumerateFiles(path); + FOR_EACH (StringVectCIter, i, list->names) + { + const std::string str = *i; + const size_t len = str.size(); + + if (len > ext.length() && + !ext.compare(str.substr(len - ext.length()))) + { + const std::string file = path + str; + const std::string realPath = VirtFs::getRealDir(file); + VirtFs::addZipToSearchPath(std::string(realPath).append( + dirSeparator).append(file), append); + } + } + VirtFs::freeList(list); + } + + void searchAndRemoveArchives(const std::string &restrict path, + const std::string &restrict ext) + { + VirtList *const list = VirtFs::enumerateFiles(path); + FOR_EACH (StringVectCIter, i, list->names) + { + const std::string str = *i; + const size_t len = str.size(); + if (len > ext.length() && + !ext.compare(str.substr(len - ext.length()))) + { + const std::string file = path + str; + const std::string realPath = VirtFs::getRealDir(file); + VirtFs::removeZipFromSearchPath(std::string( + realPath).append( + dirSeparator).append( + file)); + } + } + VirtFs::freeList(list); + } + + void getFilesWithDir(const std::string &path, + StringVect &list) + { + VirtList *const fonts = VirtFs::enumerateFiles(path); + FOR_EACH (StringVectCIter, i, fonts->names) + { + if (!VirtFs::isDirectory(path + *i)) + list.push_back(path + *i); + } + VirtFs::freeList(fonts); + } + + void getFilesInDir(const std::string &dir, + StringVect &list, + const std::string &ext) + { + const std::string path = dir + "/"; + StringVect tempList; + VirtFs::getFilesWithDir(path, tempList); + FOR_EACH (StringVectCIter, it, tempList) + { + const std::string &str = *it; + if (findLast(str, ext)) + list.push_back(str); + } + std::sort(list.begin(), list.end()); + } + + void getFiles(const std::string &path, + StringVect &list) + { + VirtList *const fonts = VirtFs::enumerateFiles(path); + FOR_EACH (StringVectCIter, i, fonts->names) + { + if (!VirtFs::isDirectory(path + dirSeparator + *i)) + list.push_back(*i); + } + VirtFs::freeList(fonts); + } + + void getDirs(const std::string &path, StringVect &list) + { + VirtList *const fonts = VirtFs::enumerateFiles(path); + FOR_EACH (StringVectCIter, i, fonts->names) + { + if (VirtFs::isDirectory(path + dirSeparator + *i)) + list.push_back(*i); + } + VirtFs::freeList(fonts); + } + + std::string getPath(const std::string &file) + { + // get the real path to the file + const std::string tmp = VirtFs::getRealDir(file); + std::string path; + + // if the file is not in the search path, then its empty + if (!tmp.empty()) + { + path = std::string(tmp).append(dirSeparator).append(file); +#if defined __native_client__ + std::string dataZip = "/http/data.zip/"; + if (path.substr(0, dataZip.length()) == dataZip) + path = path.replace(0, dataZip.length(), "/http/data/"); +#endif // defined __native_client__ + } + else + { + // if not found in search path return the default path + path = getPackageDir().append(dirSeparator).append(file); + } + + return path; + } + + std::string loadTextFileString(const std::string &fileName) + { + int contentsLength; + char *fileContents = static_cast<char*>( + VirtFs::loadFile(fileName, contentsLength)); + + if (!fileContents) + { + logger->log("Couldn't load text file: %s", fileName.c_str()); + return std::string(); + } + const std::string str = std::string(fileContents, contentsLength); + free(fileContents); + return str; + } + + bool loadTextFile(const std::string &fileName, + StringVect &lines) + { + int contentsLength; + char *fileContents = static_cast<char*>( + VirtFs::loadFile(fileName, contentsLength)); + + if (!fileContents) + { + logger->log("Couldn't load text file: %s", fileName.c_str()); + return false; + } + + std::istringstream iss(std::string(fileContents, contentsLength)); + std::string line; + + while (getline(iss, line)) + lines.push_back(line); + + free(fileContents); + return true; + } +} // namespace VirtFs diff --git a/src/fs/virtfstools.h b/src/fs/virtfstools.h new file mode 100644 index 000000000..4f2a77f4c --- /dev/null +++ b/src/fs/virtfstools.h @@ -0,0 +1,54 @@ +/* + * The ManaPlus Client + * Copyright (C) 2013-2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_VIRTFSTOOLS_H +#define UTILS_VIRTFSTOOLS_H + +#include "enums/simpletypes/append.h" + +#include "utils/stringvector.h" + +#include "localconsts.h" + +namespace VirtFs +{ + void *loadFile(const std::string &restrict fileName, + int &restrict fileSize); + void searchAndAddArchives(const std::string &restrict path, + const std::string &restrict ext, + const Append append); + void searchAndRemoveArchives(const std::string &restrict path, + const std::string &restrict ext); + void getFilesInDir(const std::string &dir, + StringVect &list, + const std::string &ext); + void getFilesWithDir(const std::string &restrict path, + StringVect &restrict list); + void getFiles(const std::string &path, + StringVect &list); + void getDirs(const std::string &path, + StringVect &list); + std::string getPath(const std::string &file); + bool loadTextFile(const std::string &fileName, + StringVect &lines); + std::string loadTextFileString(const std::string &fileName); +} // namespace VirtFs + +#endif // UTILS_VIRTFSTOOLS_H diff --git a/src/fs/virtlist.cpp b/src/fs/virtlist.cpp new file mode 100644 index 000000000..d561e6b66 --- /dev/null +++ b/src/fs/virtlist.cpp @@ -0,0 +1,32 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "fs/virtlist.h" + +#include "debug.h" + +VirtList::VirtList() : + names() +{ +} + +VirtList::~VirtList() +{ +} diff --git a/src/fs/virtlist.h b/src/fs/virtlist.h new file mode 100644 index 000000000..5b1d10924 --- /dev/null +++ b/src/fs/virtlist.h @@ -0,0 +1,39 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_VIRTLIST_H +#define UTILS_VIRTLIST_H + +#include "utils/stringvector.h" + +#include "localconsts.h" + +struct VirtList final +{ + VirtList(); + + A_DELETE_COPY(VirtList) + + ~VirtList(); + + StringVect names; +}; + +#endif // UTILS_VIRTLIST_H |