3232#endif
3333
3434#include < algorithm>
35+ #include < array>
3536#include < cassert>
3637#include < charconv>
3738#include < ranges>
@@ -50,6 +51,31 @@ namespace
5051
5152constexpr std::string_view DecodeURLSpecialChars{" +%" };
5253
54+ // Lookup table for URL encoding. This is more efficient than using fmt::format
55+ // for such a simple operation and this function has been identified as a hot path
56+ // during library scans; especially encoding the contents of nfo files into URL
57+ // parameters.
58+ constexpr std::array<const char *, 256 > hex_chars{
59+ // clang-format off
60+ " %00" , " %01" , " %02" , " %03" , " %04" , " %05" , " %06" , " %07" , " %08" , " %09" , " %0a" , " %0b" , " %0c" , " %0d" , " %0e" , " %0f" ,
61+ " %10" , " %11" , " %12" , " %13" , " %14" , " %15" , " %16" , " %17" , " %18" , " %19" , " %1a" , " %1b" , " %1c" , " %1d" , " %1e" , " %1f" ,
62+ " %20" , " %21" , " %22" , " %23" , " %24" , " %25" , " %26" , " %27" , " %28" , " %29" , " %2a" , " %2b" , " %2c" , " %2d" , " %2e" , " %2f" ,
63+ " %30" , " %31" , " %32" , " %33" , " %34" , " %35" , " %36" , " %37" , " %38" , " %39" , " %3a" , " %3b" , " %3c" , " %3d" , " %3e" , " %3f" ,
64+ " %40" , " %41" , " %42" , " %43" , " %44" , " %45" , " %46" , " %47" , " %48" , " %49" , " %4a" , " %4b" , " %4c" , " %4d" , " %4e" , " %4f" ,
65+ " %50" , " %51" , " %52" , " %53" , " %54" , " %55" , " %56" , " %57" , " %58" , " %59" , " %5a" , " %5b" , " %5c" , " %5d" , " %5e" , " %5f" ,
66+ " %60" , " %61" , " %62" , " %63" , " %64" , " %65" , " %66" , " %67" , " %68" , " %69" , " %6a" , " %6b" , " %6c" , " %6d" , " %6e" , " %6f" ,
67+ " %70" , " %71" , " %72" , " %73" , " %74" , " %75" , " %76" , " %77" , " %78" , " %79" , " %7a" , " %7b" , " %7c" , " %7d" , " %7e" , " %7f" ,
68+ " %80" , " %81" , " %82" , " %83" , " %84" , " %85" , " %86" , " %87" , " %88" , " %89" , " %8a" , " %8b" , " %8c" , " %8d" , " %8e" , " %8f" ,
69+ " %90" , " %91" , " %92" , " %93" , " %94" , " %95" , " %96" , " %97" , " %98" , " %99" , " %9a" , " %9b" , " %9c" , " %9d" , " %9e" , " %9f" ,
70+ " %a0" , " %a1" , " %a2" , " %a3" , " %a4" , " %a5" , " %a6" , " %a7" , " %a8" , " %a9" , " %aa" , " %ab" , " %ac" , " %ad" , " %ae" , " %af" ,
71+ " %b0" , " %b1" , " %b2" , " %b3" , " %b4" , " %b5" , " %b6" , " %b7" , " %b8" , " %b9" , " %ba" , " %bb" , " %bc" , " %bd" , " %be" , " %bf" ,
72+ " %c0" , " %c1" , " %c2" , " %c3" , " %c4" , " %c5" , " %c6" , " %c7" , " %c8" , " %c9" , " %ca" , " %cb" , " %cc" , " %cd" , " %ce" , " %cf" ,
73+ " %d0" , " %d1" , " %d2" , " %d3" , " %d4" , " %d5" , " %d6" , " %d7" , " %d8" , " %d9" , " %da" , " %db" , " %dc" , " %dd" , " %de" , " %df" ,
74+ " %e0" , " %e1" , " %e2" , " %e3" , " %e4" , " %e5" , " %e6" , " %e7" , " %e8" , " %e9" , " %ea" , " %eb" , " %ec" , " %ed" , " %ee" , " %ef" ,
75+ " %f0" , " %f1" , " %f2" , " %f3" , " %f4" , " %f5" , " %f6" , " %f7" , " %f8" , " %f9" , " %fa" , " %fb" , " %fc" , " %fd" , " %fe" , " %ff" ,
76+ // clang-format on
77+ };
78+
5379std::optional<char > DecodeOctlet (std::string_view& encoded)
5480{
5581 if (encoded.length () < 2 )
@@ -95,15 +121,17 @@ std::string URIUtils::URLDecode(std::string_view encoded)
95121
96122std::string URIUtils::URLEncode (std::string_view decoded, std::string_view URLSpec)
97123{
98- std::ostringstream oss;
124+ std::string result;
125+ result.reserve (decoded.size () * 2 );
126+
99127 for (const auto & ch : decoded)
100128 {
101129 if (StringUtils::isasciialphanum (ch) || URLSpec.find (ch) != std::string::npos)
102- oss << ch;
130+ result += ch;
103131 else
104- fmt::format_to ( std::ostreambuf_iterator (oss), " %{:02x} " , static_cast <unsigned char >(ch));
132+ result. append (hex_chars[ static_cast <unsigned char >(ch)], 3 );
105133 }
106- return std::move (oss). str () ;
134+ return result ;
107135}
108136
109137void URIUtils::RegisterAdvancedSettings (const CAdvancedSettings& advancedSettings)
0 commit comments