allow subfolders in custom texture folders
make file iterator to be used by custom tex and game scanner added some missing nowide::getenv
This commit is contained in:
parent
b47e2abb7c
commit
87e9fdd0ac
|
@ -138,7 +138,7 @@ LogManager::LogManager()
|
|||
FileLogListener *listener = new FileLogListener(logPath);
|
||||
if (!listener->IsValid())
|
||||
{
|
||||
const char *home = getenv("HOME");
|
||||
const char *home = nowide::getenv("HOME");
|
||||
if (home != nullptr)
|
||||
{
|
||||
delete listener;
|
||||
|
|
|
@ -125,3 +125,133 @@ inline int mkdir(const char *path, mode_t mode) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// iterate depth-first over the files contained in a folder hierarchy
|
||||
class DirectoryTree
|
||||
{
|
||||
public:
|
||||
struct item {
|
||||
std::string name;
|
||||
std::string parentPath;
|
||||
};
|
||||
|
||||
class iterator
|
||||
{
|
||||
private:
|
||||
iterator(DIR *dir, std::string pathname) {
|
||||
if (dir != nullptr)
|
||||
{
|
||||
dirs.push_back(dir);
|
||||
pathnames.push_back(pathname);
|
||||
advance();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
~iterator() {
|
||||
for (DIR *dir : dirs)
|
||||
flycast::closedir(dir);
|
||||
}
|
||||
|
||||
const item *operator->() {
|
||||
if (direntry == nullptr)
|
||||
throw std::runtime_error("null iterator");
|
||||
return ¤tItem;
|
||||
}
|
||||
|
||||
const item& operator*() const {
|
||||
if (direntry == nullptr)
|
||||
throw std::runtime_error("null iterator");
|
||||
return currentItem;
|
||||
}
|
||||
|
||||
// Prefix increment
|
||||
iterator& operator++() {
|
||||
advance();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Basic (in)equality implementations, just intended to work when comparing with end() or this
|
||||
friend bool operator==(const iterator& a, const iterator& b) {
|
||||
return a.direntry == b.direntry;
|
||||
}
|
||||
|
||||
friend bool operator!=(const iterator& a, const iterator& b) {
|
||||
return a.direntry != b.direntry;
|
||||
}
|
||||
|
||||
private:
|
||||
void advance()
|
||||
{
|
||||
while (!dirs.empty())
|
||||
{
|
||||
direntry = flycast::readdir(dirs.back());
|
||||
if (direntry == nullptr)
|
||||
{
|
||||
flycast::closedir(dirs.back());
|
||||
dirs.pop_back();
|
||||
pathnames.pop_back();
|
||||
continue;
|
||||
}
|
||||
currentItem.name = direntry->d_name;
|
||||
if (currentItem.name == "." || currentItem.name == "..")
|
||||
continue;
|
||||
std::string childPath = pathnames.back() + "/" + currentItem.name;
|
||||
bool isDir = false;
|
||||
#ifndef _WIN32
|
||||
if (entry->d_type == DT_DIR)
|
||||
isDir = true;
|
||||
else if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)
|
||||
#endif
|
||||
{
|
||||
struct stat st;
|
||||
if (flycast::stat(childPath.c_str(), &st) != 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
isDir = true;
|
||||
}
|
||||
if (!isDir)
|
||||
{
|
||||
currentItem.parentPath = pathnames.back();
|
||||
break;
|
||||
}
|
||||
|
||||
DIR *childDir = flycast::opendir(childPath.c_str());
|
||||
if (childDir == nullptr)
|
||||
{
|
||||
INFO_LOG(COMMON, "Cannot read directory '%s'", childPath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
dirs.push_back(childDir);
|
||||
pathnames.push_back(childPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DIR *> dirs;
|
||||
std::vector<std::string> pathnames;
|
||||
dirent *direntry = nullptr;
|
||||
item currentItem;
|
||||
|
||||
friend class DirectoryTree;
|
||||
};
|
||||
|
||||
DirectoryTree(const std::string& root) : root(root) {
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
DIR *dir = flycast::opendir(root.c_str());
|
||||
if (dir == nullptr)
|
||||
INFO_LOG(COMMON, "Cannot read directory '%s'", root.c_str());
|
||||
|
||||
return iterator(dir, root);
|
||||
}
|
||||
iterator end()
|
||||
{
|
||||
return iterator(nullptr, root);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string& root;
|
||||
};
|
||||
|
|
|
@ -20,10 +20,7 @@
|
|||
#include "cfg/cfg.h"
|
||||
#include "oslib/directory.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <dirent.h>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STBI_ONLY_JPEG
|
||||
#define STBI_ONLY_PNG
|
||||
|
@ -41,33 +38,33 @@ void CustomTexture::LoaderThread()
|
|||
BaseTextureCacheData *texture;
|
||||
|
||||
do {
|
||||
texture = NULL;
|
||||
|
||||
work_queue_mutex.lock();
|
||||
if (!work_queue.empty())
|
||||
texture = nullptr;
|
||||
{
|
||||
texture = work_queue.back();
|
||||
work_queue.pop_back();
|
||||
std::unique_lock<std::mutex> lock(work_queue_mutex);
|
||||
if (!work_queue.empty())
|
||||
{
|
||||
texture = work_queue.back();
|
||||
work_queue.pop_back();
|
||||
}
|
||||
}
|
||||
work_queue_mutex.unlock();
|
||||
|
||||
if (texture != NULL)
|
||||
if (texture != nullptr)
|
||||
{
|
||||
texture->ComputeHash();
|
||||
if (texture->custom_image_data != NULL)
|
||||
if (texture->custom_image_data != nullptr)
|
||||
{
|
||||
free(texture->custom_image_data);
|
||||
texture->custom_image_data = NULL;
|
||||
texture->custom_image_data = nullptr;
|
||||
}
|
||||
if (!texture->dirty)
|
||||
{
|
||||
int width, height;
|
||||
u8 *image_data = LoadCustomTexture(texture->texture_hash, width, height);
|
||||
if (image_data == NULL)
|
||||
if (image_data == nullptr)
|
||||
{
|
||||
image_data = LoadCustomTexture(texture->old_texture_hash, width, height);
|
||||
}
|
||||
if (image_data != NULL)
|
||||
if (image_data != nullptr)
|
||||
{
|
||||
texture->custom_width = width;
|
||||
texture->custom_height = height;
|
||||
|
@ -77,7 +74,7 @@ void CustomTexture::LoaderThread()
|
|||
texture->custom_load_in_progress--;
|
||||
}
|
||||
|
||||
} while (texture != NULL);
|
||||
} while (texture != nullptr);
|
||||
|
||||
wakeup_thread.Wait();
|
||||
}
|
||||
|
@ -105,8 +102,8 @@ bool CustomTexture::Init()
|
|||
{
|
||||
textures_path = get_readonly_data_path("textures/" + game_id) + "/";
|
||||
|
||||
DIR *dir = opendir(textures_path.c_str());
|
||||
if (dir != NULL)
|
||||
DIR *dir = flycast::opendir(textures_path.c_str());
|
||||
if (dir != nullptr)
|
||||
{
|
||||
INFO_LOG(RENDERER, "Found custom textures directory: %s", textures_path.c_str());
|
||||
custom_textures_available = true;
|
||||
|
@ -123,9 +120,10 @@ void CustomTexture::Terminate()
|
|||
if (initialized)
|
||||
{
|
||||
initialized = false;
|
||||
work_queue_mutex.lock();
|
||||
work_queue.clear();
|
||||
work_queue_mutex.unlock();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(work_queue_mutex);
|
||||
work_queue.clear();
|
||||
}
|
||||
wakeup_thread.Set();
|
||||
loader_thread.WaitToEnd();
|
||||
texture_map.clear();
|
||||
|
@ -154,9 +152,10 @@ void CustomTexture::LoadCustomTextureAsync(BaseTextureCacheData *texture_data)
|
|||
return;
|
||||
|
||||
texture_data->custom_load_in_progress++;
|
||||
work_queue_mutex.lock();
|
||||
work_queue.insert(work_queue.begin(), texture_data);
|
||||
work_queue_mutex.unlock();
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(work_queue_mutex);
|
||||
work_queue.insert(work_queue.begin(), texture_data);
|
||||
}
|
||||
wakeup_thread.Set();
|
||||
}
|
||||
|
||||
|
@ -238,35 +237,14 @@ void CustomTexture::DumpTexture(u32 hash, int w, int h, TextureType textype, voi
|
|||
void CustomTexture::LoadMap()
|
||||
{
|
||||
texture_map.clear();
|
||||
DIR *dir = flycast::opendir(textures_path.c_str());
|
||||
if (dir == nullptr)
|
||||
return;
|
||||
while (true)
|
||||
DirectoryTree tree(textures_path);
|
||||
for (const DirectoryTree::item& item : tree)
|
||||
{
|
||||
struct dirent *entry = flycast::readdir(dir);
|
||||
if (entry == nullptr)
|
||||
break;
|
||||
std::string name(entry->d_name);
|
||||
if (name == "." || name == "..")
|
||||
continue;
|
||||
std::string child_path = textures_path + name;
|
||||
#ifndef _WIN32
|
||||
if (entry->d_type == DT_DIR)
|
||||
continue;
|
||||
if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)
|
||||
#endif
|
||||
{
|
||||
struct stat st;
|
||||
if (flycast::stat(child_path.c_str(), &st) != 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
continue;
|
||||
}
|
||||
std::string extension = get_file_extension(name);
|
||||
std::string extension = get_file_extension(item.name);
|
||||
if (extension != "jpg" && extension != "jpeg" && extension != "png")
|
||||
continue;
|
||||
std::string::size_type dotpos = name.find_last_of('.');
|
||||
std::string basename = name.substr(0, dotpos);
|
||||
std::string::size_type dotpos = item.name.find_last_of('.');
|
||||
std::string basename = item.name.substr(0, dotpos);
|
||||
char *endptr;
|
||||
u32 hash = (u32)strtoll(basename.c_str(), &endptr, 16);
|
||||
if (endptr - basename.c_str() < (ptrdiff_t)basename.length())
|
||||
|
@ -274,8 +252,7 @@ void CustomTexture::LoadMap()
|
|||
INFO_LOG(RENDERER, "Invalid hash %s", basename.c_str());
|
||||
continue;
|
||||
}
|
||||
texture_map[hash] = child_path;
|
||||
texture_map[hash] = item.parentPath + "/" + item.name;
|
||||
}
|
||||
flycast::closedir(dir);
|
||||
custom_textures_available = !texture_map.empty();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
class CustomTexture {
|
||||
public:
|
||||
|
|
|
@ -55,7 +55,7 @@ class GameScanner
|
|||
|
||||
void add_game_directory(const std::string& path)
|
||||
{
|
||||
//printf("Exploring %s\n", path.c_str());
|
||||
// FIXME this won't work anymore
|
||||
if (game_list.size() == 0)
|
||||
{
|
||||
++empty_folders_scanned;
|
||||
|
@ -67,63 +67,36 @@ class GameScanner
|
|||
content_path_looks_incorrect = false;
|
||||
}
|
||||
|
||||
DIR *dir = flycast::opendir(path.c_str());
|
||||
if (dir == NULL)
|
||||
return;
|
||||
while (running)
|
||||
{
|
||||
dirent *entry = flycast::readdir(dir);
|
||||
if (entry == NULL)
|
||||
break;
|
||||
std::string name(entry->d_name);
|
||||
if (name == "." || name == "..")
|
||||
DirectoryTree tree(path);
|
||||
for (const DirectoryTree::item& item : tree)
|
||||
{
|
||||
std::string name(item.name);
|
||||
std::string child_path = item.parentPath + "/" + name;
|
||||
|
||||
std::string extension = get_file_extension(name);
|
||||
if (extension == "zip" || extension == "7z")
|
||||
{
|
||||
std::string basename = get_file_basename(name);
|
||||
string_tolower(basename);
|
||||
auto it = arcade_games.find(basename);
|
||||
if (it == arcade_games.end())
|
||||
continue;
|
||||
name = name + " (" + std::string(it->second->description) + ")";
|
||||
}
|
||||
else if (extension == "chd" || extension == "gdi")
|
||||
{
|
||||
// Hide arcade gdroms
|
||||
std::string basename = get_file_basename(name);
|
||||
string_tolower(basename);
|
||||
if (arcade_gdroms.count(basename) != 0)
|
||||
continue;
|
||||
}
|
||||
else if ((settings.dreamcast.HideLegacyNaomiRoms
|
||||
|| (extension != "bin" && extension != "lst" && extension != "dat"))
|
||||
&& extension != "cdi" && extension != "cue")
|
||||
continue;
|
||||
std::string child_path = path + "/" + name;
|
||||
bool is_dir = false;
|
||||
#ifndef _WIN32
|
||||
if (entry->d_type == DT_DIR)
|
||||
is_dir = true;
|
||||
if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)
|
||||
#endif
|
||||
{
|
||||
struct stat st;
|
||||
if (flycast::stat(child_path.c_str(), &st) != 0)
|
||||
continue;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
is_dir = true;
|
||||
}
|
||||
if (is_dir)
|
||||
{
|
||||
add_game_directory(child_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string extension = get_file_extension(name);
|
||||
if (extension == "zip" || extension == "7z")
|
||||
{
|
||||
std::string basename = get_file_basename(name);
|
||||
string_tolower(basename);
|
||||
auto it = arcade_games.find(basename);
|
||||
if (it == arcade_games.end())
|
||||
continue;
|
||||
name = name + " (" + std::string(it->second->description) + ")";
|
||||
}
|
||||
else if (extension == "chd" || extension == "gdi")
|
||||
{
|
||||
// Hide arcade gdroms
|
||||
std::string basename = get_file_basename(name);
|
||||
string_tolower(basename);
|
||||
if (arcade_gdroms.count(basename) != 0)
|
||||
continue;
|
||||
}
|
||||
else if ((settings.dreamcast.HideLegacyNaomiRoms
|
||||
|| (extension != "bin" && extension != "lst" && extension != "dat"))
|
||||
&& extension != "cdi" && extension != "cue")
|
||||
continue;
|
||||
insert_game(GameMedia{ name, child_path });
|
||||
}
|
||||
insert_game(GameMedia{ name, child_path });
|
||||
}
|
||||
flycast::closedir(dir);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -111,7 +111,7 @@ void select_directory_popup(const char *prompt, float scaling, StringCallback ca
|
|||
if (select_current_directory == PSEUDO_ROOT)
|
||||
{
|
||||
error_message = "Storage Locations";
|
||||
const char *home = getenv("REICAST_HOME");
|
||||
const char *home = nowide::getenv("REICAST_HOME");
|
||||
while (home != NULL)
|
||||
{
|
||||
const char *pcolon = strchr(home, ':');
|
||||
|
|
Loading…
Reference in New Issue