| 10831 | } |
| 10832 | |
| 10833 | std::string percent_decode(const std::string_view input, size_t first_percent) { |
| 10834 | // next line is for safety only, we expect users to avoid calling |
| 10835 | // percent_decode when first_percent is outside the range. |
| 10836 | if (first_percent == std::string_view::npos) { |
| 10837 | return std::string(input); |
| 10838 | } |
| 10839 | std::string dest; |
| 10840 | dest.reserve(input.length()); |
| 10841 | dest.append(input.substr(0, first_percent)); |
| 10842 | const char* pointer = input.data() + first_percent; |
| 10843 | const char* end = input.data() + input.size(); |
| 10844 | // Optimization opportunity: if the following code gets |
| 10845 | // called often, it can be optimized quite a bit. |
| 10846 | while (pointer < end) { |
| 10847 | const char ch = pointer[0]; |
| 10848 | size_t remaining = end - pointer - 1; |
| 10849 | if (ch != '%' || remaining < 2 || |
| 10850 | ( // ch == '%' && // It is unnecessary to check that ch == '%'. |
| 10851 | (!is_ascii_hex_digit(pointer[1]) || |
| 10852 | !is_ascii_hex_digit(pointer[2])))) { |
| 10853 | dest += ch; |
| 10854 | pointer++; |
| 10855 | } else { |
| 10856 | unsigned a = convert_hex_to_binary(pointer[1]); |
| 10857 | unsigned b = convert_hex_to_binary(pointer[2]); |
| 10858 | char c = static_cast<char>(a * 16 + b); |
| 10859 | dest += c; |
| 10860 | pointer += 3; |
| 10861 | } |
| 10862 | } |
| 10863 | return dest; |
| 10864 | } |
| 10865 | |
| 10866 | std::string percent_encode(const std::string_view input, |
| 10867 | const uint8_t character_set[]) { |
no test coverage detected