Improvements to NtQueryDirectoryFileEx

This commit is contained in:
Igor Pissolati
2025-04-24 01:03:35 -03:00
parent 02ed4fbb03
commit 97ec131c50
6 changed files with 190 additions and 26 deletions

View File

@@ -41,9 +41,7 @@ namespace utils
bool operator()(const std::string_view lhs, const std::string_view rhs) const
{
return std::ranges::equal(lhs, rhs, [](const char c1, const char c2) {
return string::char_to_lower(c1) == string::char_to_lower(c2);
});
return string::equals_ignore_case(lhs, rhs);
}
};

View File

@@ -149,4 +149,20 @@ namespace utils::string
return data;
}
template <class Elem, class Traits, class Alloc>
bool equals_ignore_case(const std::basic_string<Elem, Traits, Alloc>& lhs,
const std::basic_string<Elem, Traits, Alloc>& rhs)
{
return std::ranges::equal(lhs, rhs,
[](const auto c1, const auto c2) { return char_to_lower(c1) == char_to_lower(c2); });
}
template <class Elem, class Traits>
bool equals_ignore_case(const std::basic_string_view<Elem, Traits>& lhs,
const std::basic_string_view<Elem, Traits>& rhs)
{
return std::ranges::equal(lhs, rhs,
[](const auto c1, const auto c2) { return char_to_lower(c1) == char_to_lower(c2); });
}
}

View File

@@ -0,0 +1,99 @@
#pragma once
#include <string>
namespace utils::wildcard
{
inline bool is_wildcard(char16_t c)
{
return c == '*' || c == '?' || c == '>' || c == '<' || c == '\"';
}
inline bool has_wildcard(const std::u16string_view mask)
{
return std::ranges::any_of(mask, is_wildcard);
}
inline bool match_filename(std::u16string_view name, std::u16string_view mask)
{
if (mask.empty() || mask == u"*" || mask == u"*.*")
{
return true;
}
size_t name_pos = 0;
size_t mask_pos = 0;
size_t star_mask_pos = std::u16string_view::npos;
size_t star_name_pos = 0;
while (name_pos < name.size())
{
if (mask_pos < mask.size())
{
char16_t mask_char = mask[mask_pos];
char16_t name_char = name[name_pos];
bool char_matches;
if (mask_char == u'?' || mask_char == u'>')
{
char_matches = true;
}
else if (mask_char == u'"')
{
char_matches = name_char == u'.';
}
else
{
char_matches = string::char_to_lower(name_char) == string::char_to_lower(mask_char);
}
// Advance if current characters match
if (char_matches)
{
name_pos++;
mask_pos++;
continue;
}
// If this is a wildcard, skip all consecutive wildcards and save position for backtracking
if (mask[mask_pos] == u'*' || mask[mask_pos] == u'<')
{
mask_pos++;
while (mask_pos < mask.size() && (mask[mask_pos] == u'*' || mask[mask_pos] == u'<'))
{
mask_pos++;
}
if (mask_pos == mask.size())
{
// There is no need to continue because all that remained were star masks.
return true;
}
star_mask_pos = mask_pos;
star_name_pos = name_pos;
continue;
}
}
// The current characters didn't match...
// If we had a wildcard earlier, backtrack to it and try to match at the next position
if (star_mask_pos != std::u16string_view::npos)
{
mask_pos = star_mask_pos;
name_pos = ++star_name_pos;
continue;
}
return false;
}
// Skip any remaining wildcards in the mask
while (mask_pos < mask.size() && (mask[mask_pos] == u'*' || mask[mask_pos] == u'<'))
{
mask_pos++;
}
return mask_pos == mask.size();
}
}