/
githubmirror
/
PowerToys
Обзор
Документация
Войти
/
githubmirror
/
PowerToys
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/modules/NewPlus/NewShellExtensionContextMenu/helpers_variables.h
181 строка
6 KB
Christian Gaarden Gaardmark
New+: Fixed issue with files and folders containing only numbers (#45439)
02 мар 2026, 17:16
Не верифицирован
02 мар 2026, 17:16
7e3f9f0
Код
Авторство
О чём код?
#pragma once #include <regex> #include "Helpers.h" #include "helpers_filesystem.h" #pragma comment(lib, "Pathcch.lib") namespace newplus::helpers::variables { inline std::wstring resolve_an_environment_variable(const std::wstring& string) { std::wstring return_string = string; wchar_t* env_variable = nullptr; _wdupenv_s(&env_variable, nullptr, return_string.c_str()); if (env_variable != nullptr) { return_string = env_variable; free(env_variable); } return return_string; } inline std::wstring resolve_date_time_variables(const std::wstring& string) { SYSTEMTIME local_now = { 0 }; GetLocalTime(&local_now); wchar_t resolved_filename[MAX_PATH] = { 0 }; GetDatedFileName(resolved_filename, ARRAYSIZE(resolved_filename), string.c_str(), local_now); return resolved_filename; } inline std::wstring replace_all_occurrences(const std::wstring& string, const std::wstring& search_for, const std::wstring& replacement) { std::wstring return_string = string; size_t pos = 0; while ((pos = return_string.find(search_for, pos)) != std::wstring::npos) { return_string.replace(pos, search_for.length(), replacement); pos += replacement.length(); } return return_string; } inline std::wstring resolve_environment_variables(const std::wstring& string) { // Do case-insensitive string replacement of environment variables being consistent with normal %eNV_VaR% behavior std::wstring return_string = string; const std::wregex reg_expression(L"%([^%]+)%"); std::wsmatch match; size_t start = 0; while (std::regex_search(return_string.cbegin() + start, return_string.cend(), match, reg_expression)) { std::wstring env_var_name = match[1].str(); std::wstring env_var_value = resolve_an_environment_variable(env_var_name); if (!env_var_value.empty()) { size_t match_position = match.position(0) + start; return_string.replace(match_position, match.length(0), env_var_value); start = match_position + env_var_value.length(); } else { start += match.position(0) + match.length(0); } } return return_string; } inline std::wstring resolve_parent_folder(const std::wstring& string, const std::wstring& parent_folder_name) { // Do case-sensitive string replacement, for consistency on variables designated with $ std::wstring result = replace_all_occurrences(string, constants::non_localizable::parent_folder_name_variable, parent_folder_name); return result; } inline std::filesystem::path resolve_variables_in_filename(const std::wstring& filename, const std::wstring& parent_folder_name) { std::wstring result; result = resolve_date_time_variables(filename); result = resolve_environment_variables(result); if (!parent_folder_name.empty()) { result = resolve_parent_folder(result, parent_folder_name); } result = newplus::helpers::filesystem::make_valid_filename(result); return result; } inline std::filesystem::path resolve_variables_in_path(const std::filesystem::path& path) { // Need to resolve the whole path top-down (root to leaf), because of the support for $PARENT_FOLDER_NAME std::filesystem::path result; std::wstring previous_section; std::wstring current_section; auto path_section = path.begin(); int level = 0; while (path_section != path.end()) { previous_section = current_section; current_section = path_section->wstring(); if (level <= 1) { // Up to and including L"x:\\" result /= current_section; } else { // Past L"x:\\", e.g. L"x:\\level1" and beyond result /= resolve_variables_in_filename(current_section, previous_section); } path_section++; level++; } return result; } static bool exclude_item(const std::filesystem::path& path) { DWORD attrs = GetFileAttributesW(path.c_str()); if (attrs == INVALID_FILE_ATTRIBUTES) { return false; } // Exclude if hidden or system return (attrs & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0; } inline void resolve_variables_in_filename_and_rename_files(const std::filesystem::path& path, const bool do_rename = true) { // Depth first recursion, so that we start renaming the leaves, and avoid having to rescan for (const auto& entry : std::filesystem::directory_iterator(path)) { if (std::filesystem::is_directory(entry.status())) { resolve_variables_in_filename_and_rename_files(entry.path(), do_rename); } } // Perform the actual rename for (const auto& current : std::filesystem::directory_iterator(path)) { if (!exclude_item(current)) { const std::filesystem::path resolved_path = resolve_variables_in_path(current.path()); // Only rename if the filename is actually different const std::wstring non_resolved_leaf = current.path().filename(); const std::wstring resolved_leaf = resolved_path.filename(); if (StrCmpIW(non_resolved_leaf.c_str(), resolved_leaf.c_str()) != 0) { const std::wstring org_name = current.path(); const std::wstring new_name = current.path().parent_path() / resolved_leaf; const std::wstring really_new_name = helpers::filesystem::make_unique_path_name(new_name); // To aid with testing, only conditionally rename if (do_rename) { std::filesystem::rename(org_name, really_new_name); } } } } } }