File indexing completed on 2025-04-17 08:39:01
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MYSQL_IMPL_ESCAPE_STRING_IPP
0009 #define BOOST_MYSQL_IMPL_ESCAPE_STRING_IPP
0010
0011 #pragma once
0012
0013 #include <boost/mysql/character_set.hpp>
0014 #include <boost/mysql/client_errc.hpp>
0015 #include <boost/mysql/error_code.hpp>
0016 #include <boost/mysql/escape_string.hpp>
0017 #include <boost/mysql/string_view.hpp>
0018
0019 #include <boost/mysql/detail/output_string.hpp>
0020
0021 #include <boost/mysql/impl/internal/call_next_char.hpp>
0022
0023 namespace boost {
0024 namespace mysql {
0025 namespace detail {
0026
0027
0028 class escape_sequence
0029 {
0030 char data_[2]{};
0031
0032 public:
0033 escape_sequence() = default;
0034 escape_sequence(char ch1, char ch2) noexcept : data_{ch1, ch2} {}
0035
0036 bool is_escape() const noexcept { return data_[0] != '\0'; }
0037 string_view data() const noexcept { return string_view(data_, 2); }
0038 };
0039
0040
0041
0042 template <class Escaper>
0043 BOOST_ATTRIBUTE_NODISCARD error_code
0044 escape_impl(string_view input, character_set charset, Escaper escaper, output_string_ref output)
0045 {
0046 const char* it = input.data();
0047 const char* end = it + input.size();
0048
0049
0050
0051 const char* raw_begin = it;
0052 while (it != end)
0053 {
0054 escape_sequence seq = escaper(*it);
0055 if (seq.is_escape())
0056 {
0057
0058 output.append({raw_begin, it});
0059
0060
0061 output.append(seq.data());
0062
0063
0064 ++it;
0065
0066
0067 raw_begin = it;
0068 }
0069 else
0070 {
0071
0072 std::size_t char_size = detail::call_next_char(charset, it, end);
0073 if (char_size == 0u)
0074 return client_errc::invalid_encoding;
0075 it += char_size;
0076 }
0077 }
0078
0079
0080 output.append({raw_begin, end});
0081
0082
0083 return error_code();
0084 }
0085
0086 struct backslash_escaper
0087 {
0088 escape_sequence operator()(char input) const noexcept
0089 {
0090 switch (input)
0091 {
0092 case '\0': return {'\\', '0'};
0093 case '\n': return {'\\', 'n'};
0094 case '\r': return {'\\', 'r'};
0095 case '\\': return {'\\', '\\'};
0096 case '\'': return {'\\', '\''};
0097 case '"': return {'\\', '"'};
0098 case '\x1a': return {'\\', 'Z'};
0099 default: return escape_sequence();
0100 }
0101 };
0102 };
0103
0104 struct quote_escaper
0105 {
0106 char quot;
0107
0108 quote_escaper(char q) noexcept : quot(q) {}
0109
0110 escape_sequence operator()(char input) const noexcept
0111 {
0112 return input == quot ? escape_sequence(quot, quot) : escape_sequence();
0113 }
0114 };
0115
0116 }
0117 }
0118 }
0119
0120 boost::mysql::error_code boost::mysql::detail::escape_string(
0121 string_view input,
0122 const format_options& opts,
0123 char escape_char,
0124 output_string_ref output
0125 )
0126 {
0127 return (escape_char == '`' || !opts.backslash_escapes)
0128 ? detail::escape_impl(input, opts.charset, quote_escaper(escape_char), output)
0129 : detail::escape_impl(input, opts.charset, backslash_escaper(), output);
0130 }
0131
0132 #endif