Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/app/ui/file_selector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,18 @@ std::string FileSelector::show(
}
// else file-name specified in the entry is really a file to open...

if (m_type == FileSelectorType::Save) {
std::string finalFilename = base::get_file_name(buf);
if (const size_t fver = base::verify_filename(finalFilename); fver != std::string::npos)
{
Alert::show("Error<<Invalid filename: \"%s\"<<The name contains an invalid '%c' character.||&Go back",
finalFilename.c_str(), finalFilename[fver]);

setVisible(true);
goto again;
}
}

// does it not have extension? ...we should add the extension
// selected in the filetype combo-box
if (base::get_file_extension(buf).empty()) {
Expand Down Expand Up @@ -741,6 +753,17 @@ void FileSelector::onNewFolder()
if (currentFolder) {
std::string dirname = window.name()->text();

if (m_type == FileSelectorType::Save) {
if (const size_t fver = base::verify_filename(dirname); fver != std::string::npos)
{
Alert::show("Error<<Invalid folder name: \"%s\"<<The name contains an invalid '%c' character.||&OK",
dirname.c_str(), dirname[fver]);

setVisible(true);
return;
}
}

// Create the new directory
try {
currentFolder->createDirectory(dirname);
Expand Down
21 changes: 19 additions & 2 deletions src/base/path.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Aseprite Base Library
// Copyright (c) 2001-2016 David Capello
// Base Library
// Aseprite | Copyright (C) 2001-2016 David Capello
// LibreSprite | Copyright (C) 2026 LibreSprite contributors
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
Expand Down Expand Up @@ -243,4 +244,20 @@ int compare_filenames(const std::string& a, const std::string& b)
return 1;
}

size_t verify_filename(const std::string& filename)
{
#ifdef _WIN32
// In general, _wfopen() would fail for most of these characters *except slashes and colon*,
// but returning a meaningful error message to the user is always a nice practice.
const std::string invalidChars = ":?\"<>|*";

for (size_t it=0; it<filename.size(); ++it) {
if (invalidChars.find(filename[it]) != std::string::npos) {
return it;
}
}
#endif
return std::string::npos;
}

} // namespace base
9 changes: 7 additions & 2 deletions src/base/path.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Aseprite Base Library
// Copyright (c) 2001-2016 David Capello
// Base Library
// Aseprite | Copyright (C) 2001-2016 David Capello
// LibreSprite | Copyright (C) 2026 LibreSprite contributors
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
Expand Down Expand Up @@ -52,4 +53,8 @@ namespace base {

int compare_filenames(const std::string& a, const std::string& b);

// Does platform-specific filename pre-validation to avoid any unexpected
// edge-case behaviors caused by feeding unsolicited parameters to stdio API
// (like ':' for addressing alternate NTFS streams on Windows)
size_t verify_filename(const std::string& filename);
}
Loading