Advertisement
Guest User

Untitled

a guest
Apr 16th, 2016
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 19.54 KB | None | 0 0
  1. /*
  2.  * This file is part of EasyRPG Player.
  3.  *
  4.  * EasyRPG Player is free software: you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation, either version 3 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * EasyRPG Player 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. See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
  16.  */
  17.  
  18. // Headers
  19. #include <cerrno>
  20. #include <cstdio>
  21. #include <cstdlib>
  22. #include <algorithm>
  23. #include <fstream>
  24. #include <string>
  25. #include <vector>
  26. #include <sstream>
  27.  
  28. #include <boost/optional.hpp>
  29.  
  30. #ifdef _WIN32
  31. #  include <windows.h>
  32. #  include <shlobj.h>
  33. #  ifdef __MINGW32__
  34. #    include <dirent.h>
  35. #  elif defined(_MSC_VER)
  36. #    include "dirent_win.h"
  37. #  endif
  38. #else
  39. #  include <dirent.h>
  40. #  include <unistd.h>
  41. #  include <sys/types.h>
  42. #  include <sys/stat.h>
  43. #endif
  44.  
  45. #ifdef __ANDROID__
  46. #   include <jni.h>
  47. #   include <SDL_system.h>
  48. #endif
  49.  
  50. #include "system.h"
  51. #include "options.h"
  52. #include "utils.h"
  53. #include "filefinder.h"
  54. #include "output.h"
  55. #include "player.h"
  56. #include "registry.h"
  57. #include "main_data.h"
  58.  
  59. #ifdef _MSC_VER
  60. #  include "rtp_table_bom.h"
  61. #else
  62. #  include "rtp_table.h"
  63. #endif
  64.  
  65. #ifdef _3DS
  66. #   include <3ds.h>
  67. #endif
  68.  
  69. // MinGW shlobj.h does not define this
  70. #ifndef SHGFP_TYPE_CURRENT
  71. #define SHGFP_TYPE_CURRENT 0
  72. #endif
  73.  
  74. namespace {
  75. #ifdef SUPPORT_MOVIES
  76.     const char* const MOVIE_TYPES[] = { ".avi", ".mpg" };
  77. #endif
  78.  
  79.     typedef std::vector<EASYRPG_SHARED_PTR<FileFinder::DirectoryTree>> search_path_list;
  80.     EASYRPG_SHARED_PTR<FileFinder::DirectoryTree> game_directory_tree;
  81.     search_path_list search_paths;
  82.     std::string fonts_path;
  83.  
  84.     boost::optional<std::string> FindFile(FileFinder::DirectoryTree const& tree,
  85.                                           std::string const& dir,
  86.                                           std::string const& name,
  87.                                           char const* exts[])
  88.     {
  89.         using namespace FileFinder;
  90.  
  91. #ifdef EMSCRIPTEN
  92.         // The php filefinder should have given us an useable path
  93.         std::string em_file = MakePath(dir, name);
  94.  
  95.         if (Exists(em_file))
  96.             return em_file;
  97. #endif
  98.  
  99.         std::string const lower_dir = Utils::LowerCase(dir);
  100.         std::string const escape_symbol = Player::escape_symbol;
  101.         std::string corrected_name = Utils::LowerCase(name);
  102. #ifdef _WIN32
  103.         if (escape_symbol != "\\") {
  104. #endif
  105.             std::size_t escape_pos = corrected_name.find(escape_symbol);
  106.             while (escape_pos != std::string::npos) {
  107.                 corrected_name.erase(escape_pos, escape_symbol.length());
  108.                 corrected_name.insert(escape_pos, "/");
  109.                 escape_pos = corrected_name.find(escape_symbol);
  110.             }
  111. #ifdef _WIN32
  112.         }
  113. #endif
  114.  
  115.         string_map::const_iterator dir_it = tree.directories.find(lower_dir);
  116.         if(dir_it == tree.directories.end()) { return boost::none; }
  117.  
  118.         string_map const& dir_map = tree.sub_members.find(lower_dir)->second;
  119.  
  120.         for(char const** c = exts; *c != NULL; ++c) {
  121.             string_map::const_iterator const name_it = dir_map.find(corrected_name + *c);
  122.             if(name_it != dir_map.end()) {
  123.                 return MakePath
  124.                     (std::string(tree.directory_path).append("/")
  125.                      .append(dir_it->second), name_it->second);
  126.             }
  127.         }
  128.  
  129.         return boost::none;
  130.     }
  131.  
  132.     bool is_not_ascii_char(uint8_t c) { return c > 0x80; }
  133.  
  134.     bool is_not_ascii_filename(std::string const& n) {
  135.         return std::find_if(n.begin(), n.end(), &is_not_ascii_char) != n.end();
  136.     }
  137.  
  138.     std::string const& translate_rtp(std::string const& dir, std::string const& name) {
  139.         rtp_table_type const& table =
  140.             Player::IsRPG2k() ? RTP_TABLE_2000 : RTP_TABLE_2003;
  141.  
  142.         rtp_table_type::const_iterator dir_it = table.find(Utils::LowerCase(dir));
  143.         std::string lower_name = Utils::LowerCase(name);
  144.  
  145.         if (dir_it == table.end()) { return name; }
  146.  
  147.         std::map<std::string, std::string>::const_iterator file_it =
  148.             dir_it->second.find(lower_name);
  149.         if (file_it == dir_it->second.end()) {
  150.             if (is_not_ascii_filename(lower_name)) {
  151.                 // Linear Search: Japanese file name to English file name
  152.                 for (std::map<std::string, std::string>::const_iterator it = dir_it->second.begin(); it != file_it; ++it) {
  153.                     if (it->second == lower_name) {
  154.                         return it->first;
  155.                     }
  156.                 }
  157.             }
  158.             return name;
  159.         }
  160.         return file_it->second;
  161.     }
  162.  
  163.     std::string FindFile(const std::string &dir, const std::string& name, const char* exts[]) {
  164.         const EASYRPG_SHARED_PTR<FileFinder::DirectoryTree> tree = FileFinder::GetDirectoryTree();
  165.         boost::optional<std::string> const ret = FindFile(*tree, dir, name, exts);
  166.         if (ret != boost::none) { return *ret; }
  167.  
  168.         std::string const& rtp_name = translate_rtp(dir, name);
  169.  
  170.         for(search_path_list::const_iterator i = search_paths.begin(); i != search_paths.end(); ++i) {
  171.             if (! *i) { continue; }
  172.  
  173.             boost::optional<std::string> const ret = FindFile(*(*i), dir, name, exts);
  174.             if (ret) { return *ret; }
  175.  
  176.             boost::optional<std::string> const ret_rtp = FindFile(*(*i), dir, rtp_name, exts);
  177.             if (ret_rtp) { return *ret_rtp; }
  178.         }
  179.  
  180.         Output::Debug("Cannot find: %s/%s (%s)", dir.c_str(), name.c_str(),
  181.                         name == rtp_name ? "!" : rtp_name.c_str());
  182.  
  183.         return std::string();
  184.     }
  185. } // anonymous namespace
  186.  
  187. const EASYRPG_SHARED_PTR<FileFinder::DirectoryTree> FileFinder::GetDirectoryTree() {
  188.     return game_directory_tree;
  189. }
  190.  
  191. const EASYRPG_SHARED_PTR<FileFinder::DirectoryTree> FileFinder::CreateSaveDirectoryTree() {
  192.     std::string save_path = Main_Data::GetSavePath();
  193.  
  194.     if (!(Exists(save_path) && IsDirectory(save_path))) { return EASYRPG_SHARED_PTR<DirectoryTree>(); }
  195.  
  196.     EASYRPG_SHARED_PTR<DirectoryTree> tree = EASYRPG_MAKE_SHARED<DirectoryTree>();
  197.     tree->directory_path = save_path;
  198.  
  199.     Directory mem = GetDirectoryMembers(tree->directory_path, FILES);
  200.    
  201.     for (auto& i : mem.files) {
  202.         tree->files[i.first] = i.second;
  203.     }
  204.     for (auto& i : mem.directories) {
  205.         tree->directories[i.first] = i.second;
  206.     }
  207.  
  208.     return tree;
  209. }
  210.  
  211. void FileFinder::SetDirectoryTree(EASYRPG_SHARED_PTR<FileFinder::DirectoryTree> directory_tree) {
  212.     game_directory_tree = directory_tree;
  213. }
  214.  
  215. EASYRPG_SHARED_PTR<FileFinder::DirectoryTree> FileFinder::CreateDirectoryTree(std::string const& p, bool recursive) {
  216.     if(! (Exists(p) && IsDirectory(p))) { return EASYRPG_SHARED_PTR<DirectoryTree>(); }
  217.  
  218.     EASYRPG_SHARED_PTR<DirectoryTree> tree = EASYRPG_MAKE_SHARED<DirectoryTree>();
  219.     tree->directory_path = p;
  220.  
  221.     Directory mem = GetDirectoryMembers(tree->directory_path, ALL);
  222.    
  223.     for (auto& i : mem.files) {
  224.         tree->files[i.first] = i.second;
  225.     }
  226.     for (auto& i : mem.directories) {
  227.         tree->directories[i.first] = i.second;
  228.     }
  229.  
  230.     if (recursive) {
  231.         for (auto& i : mem.directories) {
  232.             GetDirectoryMembers(MakePath(tree->directory_path, i.second), RECURSIVE).files.swap(tree->sub_members[i.first]);
  233.         }
  234.     }
  235.  
  236.     return tree;
  237. }
  238.  
  239. std::string FileFinder::MakePath(const std::string &dir, std::string const& name) {
  240.     std::string str = dir.empty()? name : dir + "/" + name;
  241. #ifdef _WIN32
  242.     std::replace(str.begin(), str.end(), '/', '\\');
  243. #else
  244.     std::replace(str.begin(), str.end(), '\\', '/');
  245. #endif
  246.     return str;
  247. }
  248.  
  249. #ifdef _WIN32
  250. std::string GetFontsPath() {
  251.     static std::string fonts_path = "";
  252.     static bool init = false;
  253.  
  254.     if (init) {
  255.         return fonts_path;
  256.     } else {
  257.         // Retrieve the Path of the Font Directory
  258.         TCHAR path[MAX_PATH];
  259.  
  260.         if (SHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, path) == S_OK) {
  261.             char fpath[MAX_PATH];
  262. #ifdef UNICODE
  263.             WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK, path, MAX_PATH, fpath, MAX_PATH, NULL, NULL);
  264. #endif
  265.             fonts_path = FileFinder::MakePath(fpath, "");
  266.         }
  267.  
  268.         init = true;
  269.  
  270.         return fonts_path;
  271.     }
  272. }
  273.  
  274. std::string GetFontFilename(std::string const& name) {
  275.     std::string real_name = Registry::ReadStrValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", name + " (TrueType)");
  276.     if (real_name.length() > 0) {
  277.         if (FileFinder::Exists(real_name))
  278.             return real_name;
  279.         if (FileFinder::Exists(GetFontsPath() + real_name))
  280.             return GetFontsPath() + real_name;
  281.     }
  282.  
  283.     real_name = Registry::ReadStrValue(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Fonts", name + " (TrueType)");
  284.     if (real_name.length() > 0) {
  285.         if (FileFinder::Exists(real_name))
  286.             return real_name;
  287.         if (FileFinder::Exists(GetFontsPath() + real_name))
  288.             return GetFontsPath() + real_name;
  289.     }
  290.  
  291.     return name;
  292. }
  293. #endif
  294.  
  295. std::string FileFinder::FindFont(const std::string& name) {
  296.     static const char* FONTS_TYPES[] = {
  297.         ".ttf", ".ttc", ".otf", ".fon", NULL, };
  298.     std::string path = FindFile("Font", name, FONTS_TYPES);
  299.  
  300. #ifdef _WIN32
  301.     if (!path.empty()) {
  302.         return path;
  303.     }
  304.  
  305.     std::string folder_path = "";
  306.     std::string filename = name;
  307.  
  308.     size_t separator_pos = path.rfind('\\');
  309.     if (separator_pos != std::string::npos) {
  310.         folder_path = path.substr(0, separator_pos);
  311.         filename = path.substr(separator_pos, path.length() - separator_pos);
  312.     }
  313.  
  314.     std::string font_filename = GetFontFilename(filename);
  315.     if (!font_filename.empty()) {
  316.         if (FileFinder::Exists(folder_path + font_filename))
  317.             return folder_path + font_filename;
  318.  
  319.         if (FileFinder::Exists(fonts_path + font_filename))
  320.             return fonts_path + font_filename;
  321.     }
  322.  
  323.     return "";
  324. #else
  325.     return path;
  326. #endif
  327. }
  328.  
  329. static void add_rtp_path(std::string const& p) {
  330.     using namespace FileFinder;
  331.     EASYRPG_SHARED_PTR<DirectoryTree> tree(CreateDirectoryTree(p));
  332.     if(tree) {
  333.         Output::Debug("Adding %s to RTP path", p.c_str());
  334.         search_paths.push_back(tree);
  335.     }
  336. }
  337.  
  338. #if !(defined(GEKKO) || defined(__ANDROID__) || defined(EMSCRIPTEN))
  339. static void read_rtp_registry(const std::string& company, const std::string& version_str, const std::string& key) {
  340.     std::string rtp_path = Registry::ReadStrValue(HKEY_CURRENT_USER, "Software\\" + company + "\\RPG" + version_str, key);
  341.     if (!rtp_path.empty()) {
  342.         add_rtp_path(rtp_path);
  343.     }
  344.  
  345.     rtp_path = Registry::ReadStrValue(HKEY_LOCAL_MACHINE, "Software\\" + company + "\\RPG" + version_str, key);
  346.     if (!rtp_path.empty()) {
  347.         add_rtp_path(rtp_path);
  348.     }
  349. }
  350. #endif
  351.  
  352. void FileFinder::InitRtpPaths(bool warn_no_rtp_found) {
  353.     search_paths.clear();
  354.  
  355.     std::string const version_str =
  356.         Player::IsRPG2k() ? "2000" :
  357.         Player::IsRPG2k3() ? "2003" :
  358.         "";
  359.  
  360.     assert(!version_str.empty());
  361.  
  362. #ifdef EMSCRIPTEN
  363.     // No RTP support for emscripten at the moment.
  364.     return;
  365. #elif defined(GEKKO)
  366.     add_rtp_path("sd:/data/rtp/" + version_str + "/");
  367.     add_rtp_path("usb:/data/rtp/" + version_str + "/");
  368. #elif defined(__ANDROID__)
  369.     // Invoke "String getRtpPath()" in EasyRPG Activity via JNI
  370.     JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
  371.     jobject sdl_activity = (jobject)SDL_AndroidGetActivity();
  372.     jclass cls = env->GetObjectClass(sdl_activity);
  373.     jmethodID jni_getRtpPath = env->GetMethodID(cls , "getRtpPath", "()Ljava/lang/String;");
  374.     jstring return_string = (jstring)env->CallObjectMethod(sdl_activity, jni_getRtpPath);
  375.    
  376.     const char *js = env->GetStringUTFChars(return_string, NULL);
  377.     std::string cs(js);
  378.  
  379.     env->ReleaseStringUTFChars(return_string, js);
  380.     env->DeleteLocalRef(sdl_activity);
  381.     env->DeleteLocalRef(cls);
  382.  
  383.     add_rtp_path(cs + "/" + version_str + "/");
  384. #else
  385.     if (Player::IsRPG2k()) {
  386.         // Prefer original 2000 RTP over Kadokawa, because there is no
  387.         // reliable way to detect this engine and much more 2k games
  388.         // use the non-English version
  389.         read_rtp_registry("ASCII", version_str, "RuntimePackagePath");
  390.         read_rtp_registry("KADOKAWA", version_str, "RuntimePackagePath");
  391.     }
  392.     else if (Player::IsRPG2k3Legacy()) {
  393.         // Original 2003 RTP installer registry key is upper case
  394.         // and Wine registry is case insensitive but new 2k3v1.10 installer is not
  395.         // Prefer Enterbrain RTP over Kadokawa for old RPG2k3 (search order)
  396.         read_rtp_registry("Enterbrain", version_str, "RUNTIMEPACKAGEPATH");
  397.         read_rtp_registry("KADOKAWA", version_str, "RuntimePackagePath");
  398.     }
  399.     else if (Player::IsRPG2k3E()) {
  400.         // Prefer Kadokawa RTP over Enterbrain for new RPG2k3
  401.         read_rtp_registry("KADOKAWA", version_str, "RuntimePackagePath");
  402.         read_rtp_registry("Enterbrain", version_str, "RUNTIMEPACKAGEPATH");
  403.     }
  404.  
  405.     add_rtp_path("/data/rtp/" + version_str + "/");
  406. #endif
  407.  
  408.     if (Player::IsRPG2k() && getenv("RPG2K_RTP_PATH"))
  409.         add_rtp_path(getenv("RPG2K_RTP_PATH"));
  410.     else if (Player::IsRPG2k3() && getenv("RPG2K3_RTP_PATH"))
  411.         add_rtp_path(getenv("RPG2K3_RTP_PATH"));
  412.  
  413.     if (getenv("RPG_RTP_PATH")) {
  414.         add_rtp_path(getenv("RPG_RTP_PATH"));
  415.     }
  416.  
  417.     if (warn_no_rtp_found && search_paths.empty()) {
  418.         Output::Warning("RTP not found. This may create missing file errors.\n"
  419.             "Install RTP files or check they are installed fine.\n"
  420.             "If this game really does not require RTP, then add\n"
  421.             "FullPackageFlag=1 line to the RPG_RT.ini game file.");
  422.     }
  423. }
  424.  
  425. void FileFinder::Quit() {
  426.     search_paths.clear();
  427.     game_directory_tree.reset();
  428. }
  429.  
  430. FILE* FileFinder::fopenUTF8(const std::string& name_utf8, char const* mode) {
  431. #ifdef _WIN32
  432.     return _wfopen(Utils::ToWideString(name_utf8).c_str(),
  433.                    Utils::ToWideString(mode).c_str());
  434. #else
  435.     return fopen(name_utf8.c_str(), mode);
  436. #endif
  437. }
  438.  
  439. EASYRPG_SHARED_PTR<std::fstream> FileFinder::openUTF8(const std::string& name,
  440.                                                       std::ios_base::openmode m)
  441. {
  442.     EASYRPG_SHARED_PTR<std::fstream> ret(new std::fstream(
  443. #ifdef _MSC_VER
  444.         Utils::ToWideString(name).c_str(),
  445. #else
  446.         name.c_str(),
  447. #endif
  448.         m));
  449.     return (*ret)? ret : EASYRPG_SHARED_PTR<std::fstream>();
  450. }
  451.  
  452. std::string FileFinder::FindImage(const std::string& dir, const std::string& name) {
  453. #ifdef EMSCRIPTEN
  454.     return FindDefault(dir, name);
  455. #endif
  456.  
  457.     static const char* IMG_TYPES[] = { ".bmp",  ".png", ".xyz", NULL };
  458.     return FindFile(dir, name, IMG_TYPES);
  459. }
  460.  
  461. std::string FileFinder::FindDefault(const std::string& dir, const std::string& name) {
  462.     static const char* no_exts[] = {"", NULL};
  463.     return FindFile(dir, name, no_exts);
  464. }
  465.  
  466. std::string FileFinder::FindDefault(std::string const& name) {
  467.     return FindDefault(*GetDirectoryTree(), name);
  468. }
  469.  
  470. std::string FileFinder::FindDefault(const DirectoryTree& tree, const std::string& dir, const std::string& name) {
  471.     static const char* no_exts[] = { "", NULL };
  472.  
  473.     boost::optional<std::string> file = FindFile(tree, dir, name, no_exts);
  474.     if (file != boost::none) {
  475.         return *file;
  476.     }
  477.     return "";
  478. }
  479.  
  480. std::string FileFinder::FindDefault(const DirectoryTree& tree, const std::string& name) {
  481.     DirectoryTree const& p = tree;
  482.     string_map const& files = p.files;
  483.  
  484.     string_map::const_iterator const it = files.find(Utils::LowerCase(name));
  485.  
  486.     return(it != files.end()) ? MakePath(p.directory_path, it->second) : "";
  487. }
  488.  
  489. bool FileFinder::IsValidProject(DirectoryTree const & dir) {
  490.     return IsRPG2kProject(dir) || IsEasyRpgProject(dir);
  491. }
  492.  
  493. bool FileFinder::IsRPG2kProject(DirectoryTree const& dir) {
  494.     string_map::const_iterator const
  495.         ldb_it = dir.files.find(Utils::LowerCase(DATABASE_NAME)),
  496.         lmt_it = dir.files.find(Utils::LowerCase(TREEMAP_NAME));
  497.  
  498.     return(ldb_it != dir.files.end() && lmt_it != dir.files.end());
  499. }
  500.  
  501. bool FileFinder::IsEasyRpgProject(DirectoryTree const& dir){
  502.     string_map::const_iterator const
  503.         ldb_it = dir.files.find(Utils::LowerCase(DATABASE_NAME_EASYRPG)),
  504.         lmt_it = dir.files.find(Utils::LowerCase(TREEMAP_NAME_EASYRPG));
  505.  
  506.     return(ldb_it != dir.files.end() && lmt_it != dir.files.end());
  507. }
  508.  
  509. bool FileFinder::HasSavegame(DirectoryTree const& dir) {
  510.     EASYRPG_SHARED_PTR<FileFinder::DirectoryTree> tree = FileFinder::CreateSaveDirectoryTree();
  511.  
  512.     for (int i = 1; i <= 15; i++) {
  513.         std::stringstream ss;
  514.         ss << "Save" << (i <= 9 ? "0" : "") << i << ".lsd";
  515.         std::string filename = FileFinder::FindDefault(*tree, ss.str());
  516.  
  517.         if (!filename.empty()) {
  518.             return true;
  519.         }
  520.     }
  521.     return false;
  522. }
  523.  
  524. std::string FileFinder::FindMusic(const std::string& name) {
  525. #ifdef EMSCRIPTEN
  526.     return FindDefault("Music", name);
  527. #endif
  528.  
  529.     static const char* MUSIC_TYPES[] = {
  530.         ".wav", ".ogg", ".mid", ".midi", ".mp3", NULL };
  531.     return FindFile("Music", name, MUSIC_TYPES);
  532. }
  533.  
  534. std::string FileFinder::FindSound(const std::string& name) {
  535. #ifdef EMSCRIPTEN
  536.     return FindDefault("Sound", name);
  537. #endif
  538.  
  539.     static const char* SOUND_TYPES[] = {
  540.         ".wav", ".ogg", ".mp3", NULL };
  541.     return FindFile("Sound", name, SOUND_TYPES);
  542. }
  543.  
  544. bool FileFinder::Exists(std::string const& filename) {
  545. #ifdef _WIN32
  546.     return ::GetFileAttributesW(Utils::ToWideString(filename).c_str()) != (DWORD)-1;
  547. #elif defined(GEKKO)
  548.     struct stat sb;
  549.     return ::stat(filename.c_str(), &sb) == 0;
  550. #else
  551.     return ::access(filename.c_str(), F_OK) != -1;
  552. #endif
  553. }
  554.  
  555. bool FileFinder::IsDirectory(std::string const& dir) {
  556.     if (!Exists(dir)) {
  557.         return false;
  558.     }
  559.  
  560. #ifdef _3DS
  561.     DIR* d = opendir(dir.c_str());
  562.     if(d) {
  563.         closedir(d);
  564.         return true;
  565.     }
  566.     return false;
  567. #endif
  568. #ifdef _WIN32
  569.     int attribs = ::GetFileAttributesW(Utils::ToWideString(dir).c_str());
  570.     return (attribs & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
  571.           == FILE_ATTRIBUTE_DIRECTORY;
  572. #else
  573.     struct stat sb;
  574. #   if (defined(GEKKO) || defined(_3DS))
  575.     BOOST_VERIFY(::stat(dir.c_str(), &sb) != -1);
  576. #   else
  577.     BOOST_VERIFY(::lstat(dir.c_str(), &sb) != -1);
  578. #endif
  579.     return S_ISDIR(sb.st_mode);
  580. #endif
  581. }
  582.  
  583. FileFinder::Directory FileFinder::GetDirectoryMembers(const std::string& path, FileFinder::Mode const m, const std::string& parent) {
  584.     assert(FileFinder::Exists(path));
  585.     assert(FileFinder::IsDirectory(path));
  586.  
  587.     Directory result;
  588.  
  589.     result.base = path;
  590.  
  591. #ifdef _WIN32
  592. #  define DIR _WDIR
  593. #  define opendir _wopendir
  594. #  define closedir _wclosedir
  595. #  define wpath Utils::ToWideString(path)
  596. #  define dirent _wdirent
  597. #  define readdir _wreaddir
  598. #else
  599. #  define wpath path
  600. #endif
  601.  
  602.     EASYRPG_SHARED_PTR< ::DIR> dir(::opendir(wpath.c_str()), ::closedir);
  603.     if (!dir) {
  604.         Output::Debug("Error opening dir %s: %s", path.c_str(),
  605.                       ::strerror(errno));
  606.         return result;
  607.     }
  608.    
  609.     static bool has_fast_dir_stat = true;
  610.     static bool is_directory;
  611.    
  612.     struct dirent* ent;
  613.     while ((ent = ::readdir(dir.get())) != NULL) {
  614. #ifdef _WIN32
  615.         std::string const name = Utils::FromWideString(ent->d_name);
  616. #else
  617.         std::string const name = ent->d_name;
  618. #endif
  619.         if (name == "." || name == "..") { continue; }
  620.        
  621.         if (has_fast_dir_stat) {
  622.             is_directory = ent->d_type == DT_DIR;
  623.         } else {
  624.             is_directory = IsDirectory(MakePath(path, name));
  625.         }
  626.        
  627.         if (name == "." || name == "..") {
  628.             if (has_fast_dir_stat && !is_directory) {
  629.                 Output::Debug("File system does not populate type field (d_type) correctly.");
  630.                 Output::Debug("Directory parsing will be slower.");
  631.                 has_fast_dir_stat = false;
  632.             }
  633.    
  634.             continue;
  635.         }
  636.        
  637.         switch(m) {
  638.         case FILES:
  639.             if (is_directory) { continue; }
  640.             break;
  641.         case DIRECTORIES:
  642.             if (!is_directory) { continue; }
  643.             break;
  644.         case ALL:
  645.             break;
  646.         case RECURSIVE:
  647.             if (is_directory) {
  648.                 Directory rdir = GetDirectoryMembers(MakePath(path, name), RECURSIVE, MakePath(parent, name));
  649.                 result.files.insert(rdir.files.begin(), rdir.files.end());
  650.                 result.directories.insert(rdir.directories.begin(), rdir.directories.end());
  651.                 continue;
  652.             }
  653.  
  654.             result.files[Utils::LowerCase(MakePath(parent, name))] = MakePath(parent, name);
  655.             continue;
  656.         }
  657.         if (is_directory) {
  658.             result.directories[Utils::LowerCase(name)] = name;
  659.         } else {
  660.             result.files[Utils::LowerCase(name)] = name;
  661.         }
  662.     }
  663.  
  664. #ifdef _WIN32
  665. #  undef DIR
  666. #  undef opendir
  667. #  undef closedir
  668. #  undef dirent
  669. #  undef readdir
  670. #endif
  671. #undef wpath
  672.  
  673.     return result;
  674. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement