Created
December 14, 2012 23:29
-
-
Save take-cheeze/4289560 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ///////////////////////////////////////////////////////////////////////////// | |
| // This file is part of EasyRPG Player. | |
| // | |
| // EasyRPG Player 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 3 of the License, or | |
| // (at your option) any later version. | |
| // | |
| // EasyRPG Player 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 EasyRPG Player. If not, see <http://www.gnu.org/licenses/>. | |
| ///////////////////////////////////////////////////////////////////////////// | |
| //////////////////////////////////////////////////////////// | |
| // Headers | |
| //////////////////////////////////////////////////////////// | |
| #include <cerrno> | |
| #include <cstdio> | |
| #include <cstring> | |
| #include <cstdlib> | |
| #include <algorithm> | |
| #include <fstream> | |
| #include <iostream> | |
| #include <map> | |
| #include <string> | |
| #include <vector> | |
| #include <boost/optional.hpp> | |
| #include "system.h" | |
| #include "options.h" | |
| #include "utils.h" | |
| #include "filefinder.h" | |
| #include "output.h" | |
| #include "player.h" | |
| #include "main_data.h" | |
| #ifdef _MSC_VER | |
| // # include "rtp_table_bom.h" | |
| typedef std::map<std::string, std::map<std::string, std::string>> rtp_table_type; | |
| static rtp_table_type rtp_table; | |
| rtp_table_type const RTP_TABLE_2003; | |
| rtp_table_type const RTP_TABLE_2000; | |
| #else | |
| # include "rtp_table.h" | |
| #endif | |
| #ifdef _WIN32 | |
| # include "dirent_win.h" | |
| # include <windows.h> | |
| # include <shlobj.h> | |
| # include "registry_win.h" | |
| #else | |
| # include <dirent.h> | |
| # include <unistd.h> | |
| # include <sys/types.h> | |
| # include <sys/stat.h> | |
| #endif | |
| // MinGW shlobj.h does not define this | |
| #ifndef SHGFP_TYPE_CURRENT | |
| #define SHGFP_TYPE_CURRENT 0 | |
| #endif | |
| namespace { | |
| const char* const MOVIE_TYPES[] = { | |
| ".avi", ".mpg" }; | |
| typedef std::vector<EASYRPG_SHARED_PTR<FileFinder::ProjectTree> > search_path_list; | |
| search_path_list search_paths; | |
| std::string fonts_path; | |
| boost::optional<std::string> FindFile(FileFinder::ProjectTree const& tree, | |
| std::string const& dir, | |
| std::string const& name, | |
| char const* exts[]) | |
| { | |
| using namespace FileFinder; | |
| std::string const lower_dir = Utils::LowerCase(dir); | |
| string_map::const_iterator dir_it = tree.directories.find(lower_dir); | |
| if(dir_it == tree.directories.end()) { return boost::none; } | |
| string_map const& dir_map = tree.sub_members.find(lower_dir)->second; | |
| for(char const** c = exts; *c != NULL; ++c) { | |
| std::string const lower_name = Utils::LowerCase(name + *c); | |
| string_map::const_iterator const name_it = dir_map.find(lower_name); | |
| if(name_it != dir_map.end()) { | |
| return MakePath(std::string(tree.project_path).append("/") | |
| .append(dir_it->second).append("/"), | |
| name_it->second); | |
| } | |
| } | |
| return boost::none; | |
| } | |
| std::string const& translate_rtp(std::string const& dir, std::string const& name) { | |
| rtp_table_type const& table = | |
| Player::engine == Player::EngineRpg2k3? RTP_TABLE_2003: | |
| RTP_TABLE_2000; | |
| rtp_table_type::const_iterator dir_it = table.find(Utils::LowerCase(dir)); | |
| if(dir_it == table.end()) { return name; } | |
| std::map<std::string, std::string>::const_iterator file_it = | |
| dir_it->second.find(Utils::LowerCase(name)); | |
| return (file_it == dir_it->second.end())? name : file_it->second; | |
| } | |
| std::string FindFile(const std::string &dir, const std::string& name, const char* exts[]) { | |
| FileFinder::ProjectTree const& tree = FileFinder::GetProjectTree(); | |
| boost::optional<std::string> const ret = FindFile(tree, dir, name, exts); | |
| if(ret != boost::none) { return *ret; } | |
| std::string const& rtp_name = translate_rtp(dir, name); | |
| Output::Debug("RTP name %s(%s)", rtp_name.c_str(), name.c_str()); | |
| for(search_path_list::const_iterator i = search_paths.begin(); i != search_paths.end(); ++i) { | |
| if(! *i) { continue; } | |
| boost::optional<std::string> const ret = FindFile(*(*i), dir, name, exts); | |
| if(ret != boost::none) { return *ret; } | |
| if(&rtp_name == &name) { continue; } | |
| boost::optional<std::string> const ret_rtp = FindFile(*(*i), dir, rtp_name, exts); | |
| if(ret != boost::none) { return *ret_rtp; } | |
| } | |
| return ""; | |
| } | |
| } // anonymous namespace | |
| EASYRPG_SHARED_PTR<FileFinder::ProjectTree> FileFinder::CreateProjectTree(std::string const& p) { | |
| if(!Exists(p) || !IsDirectory(p)) { return EASYRPG_SHARED_PTR<ProjectTree>(); } | |
| EASYRPG_SHARED_PTR<ProjectTree> tree = EASYRPG_MAKE_SHARED<ProjectTree>(); | |
| tree->project_path = p; | |
| Directory mem = GetDirectoryMembers(tree->project_path, ALL); | |
| for(string_map::const_iterator i = mem.members.begin(); i != mem.members.end(); ++i) { | |
| (IsDirectory(MakePath(tree->project_path, i->second))? | |
| tree->directories : tree->files)[i->first] = i->second; | |
| } | |
| for(string_map::const_iterator i = tree->directories.begin(); i != tree->directories.end(); ++i) { | |
| GetDirectoryMembers(MakePath(tree->project_path, i->second), FILES) | |
| .members.swap(tree->sub_members[i->first]); | |
| } | |
| return tree; | |
| } | |
| std::string FileFinder::MakePath(const std::string &dir, std::string const& name) { | |
| std::string str = dir.empty()? name : dir + "/" + name; | |
| #ifdef _WIN32 | |
| std::replace(str.begin(), str.end(), '/', '\\'); | |
| #else | |
| std::replace(str.begin(), str.end(), '\\', '/'); | |
| #endif | |
| return str; | |
| } | |
| #ifdef _WIN32 | |
| std::string GetFontsPath() { | |
| static std::string fonts_path = ""; | |
| static bool init = false; | |
| if (init) { | |
| return fonts_path; | |
| } else { | |
| // Retrieve the Path of the Font Directory | |
| TCHAR path[MAX_PATH]; | |
| if (SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, path) == S_OK) { | |
| char fpath[MAX_PATH]; | |
| #ifdef UNICODE | |
| WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK, path, MAX_PATH, fpath, MAX_PATH, NULL, NULL); | |
| #endif | |
| fonts_path = FileFinder::MakePath(fpath, ""); | |
| } | |
| init = true; | |
| return fonts_path; | |
| } | |
| } | |
| std::string GetFontFilename(std::string const& name) { | |
| std::string real_name = Registry::ReadStrValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", name + " (TrueType)"); | |
| if (real_name.length() > 0) { | |
| if (FileFinder::Exists(real_name)) | |
| return real_name; | |
| if (FileFinder::Exists(GetFontsPath() + real_name)) | |
| return GetFontsPath() + real_name; | |
| } | |
| real_name = Registry::ReadStrValue(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", name + " (TrueType)"); | |
| if (real_name.length() > 0) { | |
| if (FileFinder::Exists(real_name)) | |
| return real_name; | |
| if (FileFinder::Exists(GetFontsPath() + real_name)) | |
| return GetFontsPath() + real_name; | |
| } | |
| return name; | |
| } | |
| #endif | |
| //////////////////////////////////////////////////////////// | |
| std::string FileFinder::FindFont(const std::string& name) { | |
| static const char* FONTS_TYPES[] = { | |
| ".ttf", ".ttc", ".otf", ".fon", NULL, }; | |
| std::string path = FindFile("Font", name, FONTS_TYPES); | |
| #ifdef _WIN32 | |
| if (!path.empty()) { | |
| return path; | |
| } | |
| std::string folder_path = ""; | |
| std::string filename = name; | |
| size_t separator_pos = path.rfind('\\'); | |
| if (separator_pos != std::string::npos) { | |
| folder_path = path.substr(0, separator_pos); | |
| filename = path.substr(separator_pos, path.length() - separator_pos); | |
| } | |
| std::string font_filename = GetFontFilename(filename); | |
| if (!font_filename.empty()) { | |
| if (FileFinder::Exists(folder_path + font_filename)) | |
| return folder_path + font_filename; | |
| if (FileFinder::Exists(fonts_path + font_filename)) | |
| return fonts_path + font_filename; | |
| } | |
| return ""; | |
| #else | |
| return path; | |
| #endif | |
| } | |
| //////////////////////////////////////////////////////////// | |
| std::string FileFinder::DefaultFont() { | |
| #ifdef _WIN32 | |
| static std::string default_font = ""; | |
| static bool init = false; | |
| if (!init) { | |
| std::string fonts[] = DEFAULT_FONTS; | |
| const std::string* pfont = fonts; | |
| while(const std::string* font = pfont++) { | |
| if (font->empty()) break; | |
| default_font = FindFont(*font); | |
| if (!default_font.empty()) break; | |
| } | |
| init = true; | |
| } | |
| return default_font; | |
| #else | |
| return "DejaVuLGCSansMono"; | |
| #endif | |
| } | |
| FileFinder::ProjectTree const& FileFinder::GetProjectTree() { | |
| static ProjectTree tree_; | |
| if(tree_.project_path != Main_Data::project_path) { | |
| EASYRPG_SHARED_PTR<ProjectTree> t = CreateProjectTree(Main_Data::project_path); | |
| assert(t.get()); | |
| tree_ = *t; | |
| } | |
| return tree_; | |
| } | |
| void FileFinder::Init() { | |
| GetProjectTree(); // empty call | |
| } | |
| static void add_rtp_path(std::string const& p) { | |
| using namespace FileFinder; | |
| EASYRPG_SHARED_PTR<ProjectTree> tree(CreateProjectTree(p)); | |
| if(tree) { | |
| Output::Debug("Adding %s to RTP path", p.c_str()); | |
| search_paths.push_back(tree); | |
| } | |
| } | |
| void FileFinder::InitRtpPaths() { | |
| std::string const version_str = | |
| Player::engine == Player::EngineRpg2k? "2000": | |
| Player::engine == Player::EngineRpg2k3? "2003": | |
| ""; | |
| assert(!version_str.empty()); | |
| #ifdef _WIN32 | |
| std::string rtp_path = Registry::ReadStrValue(HKEY_CURRENT_USER, "Software\\ASCII\\RPG" + version_str, "RuntimePackagePath"); | |
| if(! rtp_path.empty()) { add_rtp_path(rtp_path); } | |
| rtp_path = Registry::ReadStrValue(HKEY_LOCAL_MACHINE, "Software\\ASCII\\RPG" + version_str, "RuntimePackagePath"); | |
| if(! rtp_path.empty()) { add_rtp_path(rtp_path); } | |
| #elif defined(GEKKO) | |
| add_rtp_path("sd:/data/rtp/" + version_str + "/"); | |
| add_rtp_path("usb:/data/rtp/" + version_str + "/"); | |
| #else | |
| add_rtp_path("/data/rtp/" + version_str + "/"); | |
| #endif | |
| if (Player::engine == Player::EngineRpg2k && getenv("RPG2K_RTP_PATH")) | |
| add_rtp_path(getenv("RPG2K_RTP_PATH")); | |
| else if (Player::engine == Player::EngineRpg2k3 && getenv("RPG2K3_RTP_PATH")) | |
| add_rtp_path(getenv("RPG2K3_RTP_PATH")); | |
| if(getenv("RPG_RTP_PATH")) { add_rtp_path(getenv("RPG_RTP_PATH")); } | |
| } | |
| void FileFinder::Quit() { | |
| search_paths.clear(); | |
| } | |
| FILE* FileFinder::fopenUTF8(const std::string& name_utf8, char const* mode) { | |
| #ifdef _WIN32 | |
| return _wfopen(Utils::ToWideString(name_utf8).c_str(), | |
| Utils::ToWideString(mode).c_str()); | |
| #else | |
| return fopen(name_utf8.c_str(), mode); | |
| #endif | |
| } | |
| EASYRPG_SHARED_PTR<std::fstream> FileFinder::openUTF8(const std::string& name, | |
| std::ios_base::openmode m) | |
| { | |
| EASYRPG_SHARED_PTR<std::fstream> ret(new std::fstream( | |
| #ifdef _MSC_VER | |
| Utils::ToWideString(name).c_str(), | |
| #else | |
| name.c_str(), | |
| #endif | |
| m)); | |
| return (*ret)? ret : EASYRPG_SHARED_PTR<std::fstream>(); | |
| } | |
| std::string FileFinder::FindImage(const std::string& dir, const std::string& name) { | |
| static const char* IMG_TYPES[] = { | |
| ".bmp", ".png", ".xyz", ".gif", ".jpg", ".jpeg", NULL }; | |
| return FindFile(dir, name, IMG_TYPES); | |
| } | |
| std::string FileFinder::FindDefault(const std::string& dir, const std::string& name) { | |
| static const char* no_exts[] = {"", NULL}; | |
| return FindFile(dir, name, no_exts); | |
| } | |
| std::string FileFinder::FindDefault(std::string const& name) { | |
| ProjectTree const& p = GetProjectTree(); | |
| string_map const& files = p.files; | |
| string_map::const_iterator const it = files.find(Utils::LowerCase(name)); | |
| return(it != files.end())? MakePath(p.project_path, it->second) : ""; | |
| } | |
| bool FileFinder::IsRPG2kProject(ProjectTree const& dir) { | |
| string_map::const_iterator const | |
| ldb_it = dir.files.find(Utils::LowerCase(DATABASE_NAME)), | |
| lmt_it = dir.files.find(Utils::LowerCase(TREEMAP_NAME)); | |
| return(ldb_it != dir.files.end() && lmt_it != dir.files.end()); | |
| } | |
| std::string FileFinder::FindMusic(const std::string& name) { | |
| static const char* MUSIC_TYPES[] = { | |
| ".wav", ".mid", ".midi", ".ogg", ".mp3", NULL }; | |
| return FindFile("Music", name, MUSIC_TYPES); | |
| } | |
| std::string FileFinder::FindSound(const std::string& name) { | |
| static const char* SOUND_TYPES[] = { | |
| ".wav", ".ogg", ".mp3", NULL }; | |
| return FindFile("Sound", name, SOUND_TYPES); | |
| } | |
| bool FileFinder::Exists(std::string const& filename) { | |
| #ifdef _WIN32 | |
| return ::GetFileAttributesW(Utils::ToWideString(filename).c_str()) != (DWORD)-1; | |
| #else | |
| return ::access(filename.c_str(), F_OK) != -1; | |
| #endif | |
| } | |
| bool FileFinder::IsDirectory(std::string const& dir) { | |
| assert(Exists(dir)); | |
| #ifdef _WIN32 | |
| return(::GetFileAttributesW(Utils::ToWideString(dir).c_str()) & FILE_ATTRIBUTE_DIRECTORY); | |
| #else | |
| struct stat sb; | |
| BOOST_VERIFY(::stat(dir.c_str(), &sb) != -1); | |
| return S_ISDIR(sb.st_mode); | |
| #endif | |
| } | |
| FileFinder::Directory FileFinder::GetDirectoryMembers(const std::string& path, FileFinder::Mode const m) { | |
| assert(FileFinder::Exists(path)); | |
| assert(FileFinder::IsDirectory(path)); | |
| Directory result; | |
| result.base = path; | |
| #ifdef _WIN32 | |
| # define DIR _WDIR | |
| # define opendir _wopendir | |
| # define closedir _wclosedir | |
| # define wpath Utils::ToWideString(path) | |
| # define dirent _wdirent | |
| # define readdir _wreaddir | |
| #else | |
| # define wpath path | |
| #endif | |
| EASYRPG_SHARED_PTR< ::DIR> dir(::opendir(wpath.c_str()), ::closedir); | |
| if (!dir) { | |
| Output::Error("Error opening dir %s: %s", path.c_str(), | |
| ::strerror(errno)); | |
| return result; | |
| } | |
| struct dirent* ent; | |
| while ((ent = ::readdir(dir.get())) != NULL) { | |
| if (ent->d_name[0] == '.') { continue; } | |
| #ifdef _WIN32 | |
| std::string const name = Utils::FromWideString(ent->d_name); | |
| #else | |
| std::string const name = ent->d_name; | |
| #endif | |
| switch(m) { | |
| case FILES: | |
| if(IsDirectory(MakePath(path, name))) { continue; } | |
| else{ break; } | |
| case DIRECTORIES: | |
| if(! IsDirectory(MakePath(path, name))) { continue; } | |
| else{ break; } | |
| case ALL: | |
| break; | |
| } | |
| result.members[Utils::LowerCase(name)] = name; | |
| } | |
| #ifdef _WIN32 | |
| # undef DIR | |
| # undef opendir | |
| # undef closedir | |
| # undef dirent | |
| # undef readdir | |
| #endif | |
| #undef wpath | |
| return result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment