mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #16805 from CookiePLMonster/cmdline-sprite-fix
Refactor path_end_with_separator and filename_valid_characters
This commit is contained in:
commit
2cd075f6e7
|
@ -579,7 +579,7 @@ static void WindowLoadsaveTextinput(rct_window* w, rct_widgetindex widgetIndex,
|
|||
{
|
||||
case WIDX_NEW_FOLDER:
|
||||
{
|
||||
if (!filename_valid_characters(text))
|
||||
if (!Platform::IsFilenameValid(text))
|
||||
{
|
||||
context_show_error(STR_ERROR_INVALID_CHARACTERS, STR_NONE, {});
|
||||
return;
|
||||
|
@ -971,7 +971,7 @@ static bool IsValidPath(const char* path)
|
|||
// which handles multiple patterns
|
||||
auto filename = Path::GetFileNameWithoutExtension(path);
|
||||
|
||||
return filename_valid_characters(filename.c_str());
|
||||
return Platform::IsFilenameValid(filename);
|
||||
}
|
||||
|
||||
static void WindowLoadsaveSelect(rct_window* w, const char* path)
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Formatter.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/platform/Platform.h>
|
||||
#include <openrct2/sprites.h>
|
||||
#include <openrct2/util/Util.h>
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -698,7 +698,7 @@ static void WindowThemesTextinput(rct_window* w, rct_widgetindex widgetIndex, ch
|
|||
{
|
||||
case WIDX_THEMES_DUPLICATE_BUTTON:
|
||||
case WIDX_THEMES_RENAME_BUTTON:
|
||||
if (filename_valid_characters(text))
|
||||
if (Platform::IsFilenameValid(text))
|
||||
{
|
||||
if (ThemeGetIndexForName(text) == SIZE_MAX)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <openrct2/localisation/Formatting.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/object/ObjectManager.h>
|
||||
#include <openrct2/platform/Platform.h>
|
||||
#include <openrct2/scenario/Scenario.h>
|
||||
#include <openrct2/scenario/ScenarioRepository.h>
|
||||
#include <openrct2/scenario/ScenarioSources.h>
|
||||
|
@ -32,7 +33,6 @@
|
|||
#include <openrct2/title/TitleSequence.h>
|
||||
#include <openrct2/title/TitleSequenceManager.h>
|
||||
#include <openrct2/title/TitleSequencePlayer.h>
|
||||
#include <openrct2/util/Util.h>
|
||||
#include <openrct2/windows/Intent.h>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
@ -635,7 +635,7 @@ static void WindowTitleEditorTextinput(rct_window* w, rct_widgetindex widgetInde
|
|||
case WIDX_TITLE_EDITOR_NEW_BUTTON:
|
||||
case WIDX_TITLE_EDITOR_DUPLICATE_BUTTON:
|
||||
case WIDX_TITLE_EDITOR_RENAME_BUTTON:
|
||||
if (filename_valid_characters(text))
|
||||
if (Platform::IsFilenameValid(text))
|
||||
{
|
||||
if (title_sequence_manager_get_index_for_name(text) == SIZE_MAX)
|
||||
{
|
||||
|
@ -1137,7 +1137,7 @@ static void WindowTitleEditorAddParkCallback(int32_t result, const utf8* path)
|
|||
|
||||
static void WindowTitleEditorRenamePark(size_t index, const utf8* name)
|
||||
{
|
||||
if (!filename_valid_characters(name))
|
||||
if (!Platform::IsFilenameValid(name))
|
||||
{
|
||||
context_show_error(STR_ERROR_INVALID_CHARACTERS, STR_NONE, {});
|
||||
return;
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/localisation/Formatter.h>
|
||||
#include <openrct2/localisation/Localisation.h>
|
||||
#include <openrct2/platform/Platform.h>
|
||||
#include <openrct2/ride/TrackDesignRepository.h>
|
||||
#include <openrct2/util/Util.h>
|
||||
|
||||
static constexpr const rct_string_id WINDOW_TITLE = STR_STRING;
|
||||
static constexpr const int32_t WH = 44;
|
||||
|
@ -164,7 +164,7 @@ static void WindowTrackManageTextinput(rct_window* w, rct_widgetindex widgetInde
|
|||
return;
|
||||
}
|
||||
|
||||
if (!filename_valid_characters(text))
|
||||
if (!Platform::IsFilenameValid(text))
|
||||
{
|
||||
context_show_error(STR_CANT_RENAME_TRACK_DESIGN, STR_NEW_NAME_CONTAINS_INVALID_CHARACTERS, {});
|
||||
return;
|
||||
|
|
|
@ -27,9 +27,9 @@
|
|||
#include <cstring>
|
||||
#include <optional>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "core/String.hpp"
|
||||
#endif
|
||||
// TODO: Remove when C++20 is enabled and std::format can be used
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
using namespace OpenRCT2::Drawing;
|
||||
|
||||
|
@ -183,12 +183,11 @@ bool SpriteFile::Save(const utf8* path)
|
|||
}
|
||||
}
|
||||
|
||||
static bool SpriteImageExport(const rct_g1_element& spriteElement, const char* outPath)
|
||||
static bool SpriteImageExport(const rct_g1_element& spriteElement, u8string_view outPath)
|
||||
{
|
||||
const auto pixelBufferSize = spriteElement.width * spriteElement.height;
|
||||
const size_t pixelBufferSize = static_cast<size_t>(spriteElement.width) * spriteElement.height;
|
||||
auto pixelBuffer = std::make_unique<uint8_t[]>(pixelBufferSize);
|
||||
auto pixels = pixelBuffer.get();
|
||||
std::fill_n(pixels, pixelBufferSize, 0x00);
|
||||
|
||||
rct_drawpixelinfo dpi;
|
||||
dpi.bits = pixels;
|
||||
|
@ -255,6 +254,15 @@ static std::optional<ImageImporter::ImportResult> SpriteImageImport(
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Remove when C++20 is enabled and std::format can be used
|
||||
static std::string PopStr(std::ostringstream& oss)
|
||||
{
|
||||
auto str = oss.str();
|
||||
oss.str("");
|
||||
oss.clear();
|
||||
return str;
|
||||
}
|
||||
|
||||
int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
||||
{
|
||||
gOpenRCT2Headless = true;
|
||||
|
@ -271,7 +279,7 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
|
||||
if (argc == 2)
|
||||
{
|
||||
const char* spriteFilePath = argv[1];
|
||||
const utf8* spriteFilePath = argv[1];
|
||||
auto spriteFile = SpriteFile::Open(spriteFilePath);
|
||||
if (!spriteFile.has_value())
|
||||
{
|
||||
|
@ -284,7 +292,7 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return 1;
|
||||
}
|
||||
|
||||
const char* spriteFilePath = argv[1];
|
||||
const utf8* spriteFilePath = argv[1];
|
||||
int32_t spriteIndex = atoi(argv[2]);
|
||||
auto spriteFile = SpriteFile::Open(spriteFilePath);
|
||||
if (!spriteFile.has_value())
|
||||
|
@ -316,9 +324,9 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
const char* spriteFilePath = argv[1];
|
||||
const utf8* spriteFilePath = argv[1];
|
||||
int32_t spriteIndex = atoi(argv[2]);
|
||||
const char* outputPath = argv[3];
|
||||
const utf8* outputPath = argv[3];
|
||||
auto spriteFile = SpriteFile::Open(spriteFilePath);
|
||||
if (!spriteFile.has_value())
|
||||
{
|
||||
|
@ -349,8 +357,8 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
const char* spriteFilePath = argv[1];
|
||||
char outputPath[MAX_PATH];
|
||||
const utf8* spriteFilePath = argv[1];
|
||||
const utf8* outputPath = argv[2];
|
||||
|
||||
auto spriteFile = SpriteFile::Open(spriteFilePath);
|
||||
if (!spriteFile.has_value())
|
||||
|
@ -359,55 +367,29 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
safe_strcpy(outputPath, argv[2], MAX_PATH);
|
||||
path_end_with_separator(outputPath, MAX_PATH);
|
||||
|
||||
if (!Platform::EnsureDirectoryExists(outputPath))
|
||||
{
|
||||
fprintf(stderr, "Unable to create directory.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t maxIndex = static_cast<int32_t>(spriteFile->Header.num_entries);
|
||||
int32_t numbers = static_cast<int32_t>(std::floor(std::log(maxIndex)));
|
||||
size_t pathLen = strlen(outputPath);
|
||||
const uint32_t maxIndex = spriteFile->Header.num_entries;
|
||||
const int32_t numbers = static_cast<int32_t>(std::floor(std::log10(maxIndex) + 1));
|
||||
|
||||
if (pathLen >= static_cast<size_t>(MAX_PATH - numbers - 5))
|
||||
std::ostringstream oss; // TODO: Remove when C++20 is enabled and std::format can be used
|
||||
for (uint32_t spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++)
|
||||
{
|
||||
fprintf(stderr, "Path too long.\n");
|
||||
return -1;
|
||||
}
|
||||
// Status indicator
|
||||
printf("\r%u / %u, %u%%", spriteIndex + 1, maxIndex, ((spriteIndex + 1) * 100) / maxIndex);
|
||||
|
||||
for (int32_t x = 0; x < numbers; x++)
|
||||
{
|
||||
outputPath[pathLen + x] = '0';
|
||||
}
|
||||
safe_strcpy(outputPath + pathLen + numbers, ".png", MAX_PATH - pathLen - numbers);
|
||||
|
||||
for (int32_t spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++)
|
||||
{
|
||||
if (spriteIndex % 100 == 99)
|
||||
{
|
||||
// Status indicator
|
||||
printf("\r%d / %d, %d%%", spriteIndex, maxIndex, spriteIndex / maxIndex);
|
||||
}
|
||||
oss << std::setw(numbers) << std::setfill('0') << spriteIndex << ".png";
|
||||
|
||||
const auto& spriteHeader = spriteFile->Entries[spriteIndex];
|
||||
if (!SpriteImageExport(spriteHeader, outputPath))
|
||||
if (!SpriteImageExport(spriteHeader, Path::Combine(outputPath, PopStr(oss))))
|
||||
{
|
||||
fprintf(stderr, "Could not export\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add to the index at the end of the file name
|
||||
char* counter = outputPath + pathLen + numbers - 1;
|
||||
(*counter)++;
|
||||
while (*counter > '9')
|
||||
{
|
||||
*counter = '0';
|
||||
counter--;
|
||||
(*counter)++;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -420,14 +402,8 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
char datName[DAT_NAME_LENGTH + 1] = { 0 };
|
||||
std::fill_n(datName, DAT_NAME_LENGTH, ' ');
|
||||
int32_t i = 0;
|
||||
for (const char* ch = argv[1]; *ch != '\0' && i < DAT_NAME_LENGTH; ch++)
|
||||
{
|
||||
datName[i++] = *ch;
|
||||
}
|
||||
|
||||
const char* datName = argv[1];
|
||||
const utf8* outputPath = argv[2];
|
||||
auto context = OpenRCT2::CreateContext();
|
||||
context->Initialise();
|
||||
|
||||
|
@ -451,53 +427,29 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
auto& objManager = context->GetObjectManager();
|
||||
const auto* const metaObject = objManager.GetLoadedObject(objectType, entryIndex);
|
||||
|
||||
char outputPath[MAX_PATH];
|
||||
safe_strcpy(outputPath, argv[2], MAX_PATH);
|
||||
path_end_with_separator(outputPath, MAX_PATH);
|
||||
|
||||
if (!Platform::EnsureDirectoryExists(outputPath))
|
||||
{
|
||||
fprintf(stderr, "Unable to create directory.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto maxIndex = metaObject->GetNumImages();
|
||||
|
||||
int32_t numDigits = std::max(1, static_cast<int32_t>(std::floor(std::log(maxIndex))));
|
||||
size_t pathLen = strlen(outputPath);
|
||||
|
||||
if (pathLen >= static_cast<size_t>(MAX_PATH - numDigits - 5))
|
||||
{
|
||||
fprintf(stderr, "Path too long.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int32_t x = 0; x < numDigits; x++)
|
||||
{
|
||||
outputPath[pathLen + x] = '0';
|
||||
}
|
||||
safe_strcpy(outputPath + pathLen + numDigits, ".png", MAX_PATH - pathLen - numDigits);
|
||||
const uint32_t maxIndex = metaObject->GetNumImages();
|
||||
const int32_t numbers = static_cast<int32_t>(std::floor(std::log10(maxIndex) + 1));
|
||||
|
||||
std::ostringstream oss; // TODO: Remove when C++20 is enabled and std::format can be used
|
||||
for (uint32_t spriteIndex = 0; spriteIndex < maxIndex; spriteIndex++)
|
||||
{
|
||||
oss << std::setw(numbers) << std::setfill('0') << spriteIndex << ".png";
|
||||
auto path = Path::Combine(outputPath, PopStr(oss));
|
||||
|
||||
const auto& g1 = metaObject->GetImageTable().GetImages()[spriteIndex];
|
||||
if (!SpriteImageExport(g1, outputPath))
|
||||
if (!SpriteImageExport(g1, path))
|
||||
{
|
||||
fprintf(stderr, "Could not export\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "{ \"path\": \"%s\", \"x\": %d, \"y\": %d },\n", outputPath, g1.x_offset, g1.y_offset);
|
||||
|
||||
// Add to the index at the end of the file name
|
||||
char* counter = outputPath + pathLen + numDigits - 1;
|
||||
(*counter)++;
|
||||
while (*counter > '9')
|
||||
{
|
||||
*counter = '0';
|
||||
counter--;
|
||||
(*counter)++;
|
||||
}
|
||||
fprintf(stdout, "{ \"path\": \"%s\", \"x\": %d, \"y\": %d },\n", path.c_str(), g1.x_offset, g1.y_offset);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -510,7 +462,7 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
const char* spriteFilePath = argv[1];
|
||||
const utf8* spriteFilePath = argv[1];
|
||||
|
||||
SpriteFile spriteFile;
|
||||
spriteFile.Save(spriteFilePath);
|
||||
|
@ -525,8 +477,8 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
const char* spriteFilePath = argv[1];
|
||||
const char* imagePath = argv[2];
|
||||
const utf8* spriteFilePath = argv[1];
|
||||
const utf8* imagePath = argv[2];
|
||||
int16_t x_offset = 0;
|
||||
int16_t y_offset = 0;
|
||||
|
||||
|
@ -577,8 +529,8 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
const char* spriteFilePath = argv[1];
|
||||
const char* spriteDescriptionPath = argv[2];
|
||||
const utf8* spriteFilePath = argv[1];
|
||||
const utf8* spriteDescriptionPath = argv[2];
|
||||
const auto directoryPath = Path::GetDirectory(spriteDescriptionPath);
|
||||
|
||||
json_t jsonSprites = Json::ReadFromFile(spriteDescriptionPath);
|
||||
|
|
|
@ -71,6 +71,7 @@ namespace Platform
|
|||
uint64_t GetFileSize(std::string_view path);
|
||||
std::string ResolveCasing(std::string_view path, bool fileExists);
|
||||
std::string SanitiseFilename(std::string_view originalName);
|
||||
bool IsFilenameValid(u8string_view fileName);
|
||||
|
||||
uint16_t GetLocaleLanguage();
|
||||
CurrencyType GetLocaleCurrency();
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
#include <cstring>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
static constexpr std::array _prohibitedCharacters = { '<', '>', '*', '\\', ':', '|', '?', '"', '/' };
|
||||
#else
|
||||
static constexpr std::array _prohibitedCharacters = { '/' };
|
||||
#endif
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
void CoreInit()
|
||||
|
@ -96,22 +102,22 @@ namespace Platform
|
|||
|
||||
std::string SanitiseFilename(std::string_view originalName)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static constexpr std::array prohibited = { '<', '>', '*', '\\', ':', '|', '?', '"', '/' };
|
||||
#else
|
||||
static constexpr std::array prohibited = { '/' };
|
||||
#endif
|
||||
auto sanitised = std::string(originalName);
|
||||
std::replace_if(
|
||||
sanitised.begin(), sanitised.end(),
|
||||
[](const std::string::value_type& ch) -> bool {
|
||||
return std::find(prohibited.begin(), prohibited.end(), ch) != prohibited.end();
|
||||
return std::find(_prohibitedCharacters.begin(), _prohibitedCharacters.end(), ch) != _prohibitedCharacters.end();
|
||||
},
|
||||
'_');
|
||||
sanitised = String::Trim(sanitised);
|
||||
return sanitised;
|
||||
}
|
||||
|
||||
bool IsFilenameValid(u8string_view fileName)
|
||||
{
|
||||
return fileName.find_first_of(_prohibitedCharacters.data(), 0, _prohibitedCharacters.size()) == fileName.npos;
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
float GetDefaultScale()
|
||||
{
|
||||
|
|
|
@ -51,29 +51,6 @@ int32_t mph_to_dmps(int32_t mph)
|
|||
return (mph * 73243) >> 14;
|
||||
}
|
||||
|
||||
bool filename_valid_characters(const utf8* filename)
|
||||
{
|
||||
for (int32_t i = 0; filename[i] != '\0'; i++)
|
||||
{
|
||||
if (filename[i] == '\\' || filename[i] == '/' || filename[i] == ':' || filename[i] == '?' || filename[i] == '*'
|
||||
|| filename[i] == '<' || filename[i] == '>' || filename[i] == '|')
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void path_end_with_separator(utf8* path, size_t size)
|
||||
{
|
||||
size_t length = strnlen(path, size);
|
||||
if (length >= size - 1)
|
||||
return;
|
||||
|
||||
if ((length == 0) || ((path[length - 1] != *PATH_SEPARATOR) && path[length - 1] != '/'))
|
||||
{
|
||||
safe_strcat(path, PATH_SEPARATOR, size);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t bitscanforward(int32_t source)
|
||||
{
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400) // Visual Studio 2005
|
||||
|
|
|
@ -23,10 +23,6 @@ int32_t metres_to_feet(int32_t metres);
|
|||
int32_t mph_to_kmph(int32_t mph);
|
||||
int32_t mph_to_dmps(int32_t mph);
|
||||
|
||||
bool filename_valid_characters(const utf8* filename);
|
||||
|
||||
void path_end_with_separator(utf8* path, size_t size);
|
||||
|
||||
bool sse41_available();
|
||||
bool avx2_available();
|
||||
|
||||
|
|
Loading…
Reference in New Issue