etternagame/etterna

[Bug]: Pack banners with uppercase file extensions are not loaded

niet-dev opened this issue · 2 comments

Is there an existing issue for this?

  • I have searched the existing issues

Contact Details

Reply to the issue, or Discord: nietscape

Version Info

Latest available release

What operating system are you seeing the problem on?

Windows

Bug Behavior

If a pack banner has an uppercase file extension, the banner is not loaded. This is uncommon, but true for some packs that are downloaded in-game.

Expected Behavior

The banner should be displayed as if it had a lowercase file extension.

Reproduction Steps

  1. Open the game
  2. Download a pack like NBJS2 or midare megapack 5
  3. Notice the pack banner does not appear
  4. Go to the pack directory, change the file extension to lowercase (bn.PNG > bn.png, bn.JPG > bn.jpg)
  5. Restart etterna, pack banner appears

Anything else?

This is only true of pack banners. Chart banners with uppercase file extensions are loaded just fine (see Blockbuster, Comsten from NBJS2).

a really fast way to try to fix it is by modifying this

std::string
GetExtension(const std::string& sPath)
{
const auto pos = sPath.rfind('.');
if (pos == std::string::npos)
return std::string();
const auto slash = sPath.find('/', pos);
if (slash != std::string::npos)
return std::string(); /* rare: path/dir.ext/fn */
return sPath.substr(pos + 1, sPath.size() - pos + 1);
}

but it is also possible that filesystems care too much about case sensitivity for that to work. we can instead change the logic here to make it more general

void
ActorUtil::InitFileTypeLists()
{
// This function creates things to serve two purposes:
// 1. A map from extensions to filetypes, so extensions can be converted.
// 2. A reverse map for things that need a list of extensions to look for.
// The first section creates the map from extensions to filetypes, then the
// second section uses that map to build the reverse map.
ExtensionToFileType["lua"] = FT_Lua;
ExtensionToFileType["xml"] = FT_Xml;
ExtensionToFileType["ini"] = FT_Ini;
// Update RageSurfaceUtils when adding new image formats.
ExtensionToFileType["bmp"] = FT_Bitmap;
ExtensionToFileType["gif"] = FT_Bitmap;
ExtensionToFileType["jpeg"] = FT_Bitmap;
ExtensionToFileType["jpg"] = FT_Bitmap;
ExtensionToFileType["png"] = FT_Bitmap;
// Update RageSoundReader_FileReader when adding new sound formats.
ExtensionToFileType["mp3"] = FT_Sound;
ExtensionToFileType["oga"] = FT_Sound;
ExtensionToFileType["ogg"] = FT_Sound;
ExtensionToFileType["wav"] = FT_Sound;
// ffmpeg takes care of loading videos, not sure whether this list should
// have everything ffmpeg supports.
ExtensionToFileType["avi"] = FT_Movie;
ExtensionToFileType["f4v"] = FT_Movie;
ExtensionToFileType["flv"] = FT_Movie;
ExtensionToFileType["mkv"] = FT_Movie;
ExtensionToFileType["mp4"] = FT_Movie;
ExtensionToFileType["mpeg"] = FT_Movie;
ExtensionToFileType["mpg"] = FT_Movie;
ExtensionToFileType["mov"] = FT_Movie;
ExtensionToFileType["ogv"] = FT_Movie;
ExtensionToFileType["webm"] = FT_Movie;
ExtensionToFileType["wmv"] = FT_Movie;
ExtensionToFileType["sprite"] = FT_Sprite;
ExtensionToFileType["txt"] = FT_Model;
// When adding new extensions, do not add them below this line. This line
// marks the point where the function switches to building the reverse map.
for (auto& curr_ext : ExtensionToFileType) {
FileTypeToExtensionList[curr_ext.second].push_back(curr_ext.first);
}
}
std::vector<std::string> const&
ActorUtil::GetTypeExtensionList(FileType ft)
{
return FileTypeToExtensionList[ft];
}
void
ActorUtil::AddTypeExtensionsToList(FileType ft, std::vector<std::string>& add_to)
{
auto ext_list = FileTypeToExtensionList.find(ft);
if (ext_list != FileTypeToExtensionList.end()) {
add_to.reserve(add_to.size() + ext_list->second.size());
for (auto& curr : ext_list->second) {
add_to.push_back(curr);
}
}
}
FileType
ActorUtil::GetFileType(const std::string& sPath)
{
const auto sExt = make_lower(GetExtension(sPath));
const auto conversion_entry = ExtensionToFileType.find(sExt);
if (conversion_entry != ExtensionToFileType.end()) {
return conversion_entry->second;
}
if (!sPath.empty() && sPath[sPath.size() - 1] == '/') {
return FT_Directory;
}
/* Do this last, to avoid the IsADirectory in most cases. */
if (IsADirectory(sPath)) {
return FT_Directory;
}
return FileType_Invalid;
}