123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- //
- // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- #ifndef BOOST_MYSQL_IMPL_ESCAPE_STRING_IPP
- #define BOOST_MYSQL_IMPL_ESCAPE_STRING_IPP
- #pragma once
- #include <boost/mysql/character_set.hpp>
- #include <boost/mysql/client_errc.hpp>
- #include <boost/mysql/error_code.hpp>
- #include <boost/mysql/escape_string.hpp>
- #include <boost/mysql/string_view.hpp>
- #include <boost/mysql/detail/output_string.hpp>
- #include <boost/mysql/impl/internal/call_next_char.hpp>
- namespace boost {
- namespace mysql {
- namespace detail {
- // A (possibly null) escape sequence of two characters. Used as the return value for escapers
- class escape_sequence
- {
- char data_[2]{};
- public:
- escape_sequence() = default;
- escape_sequence(char ch1, char ch2) noexcept : data_{ch1, ch2} {}
- bool is_escape() const noexcept { return data_[0] != '\0'; }
- string_view data() const noexcept { return string_view(data_, 2); }
- };
- // Escaper is a function object that takes a char and returns a
- // escape_sequence determining whether we should escape the char or not
- template <class Escaper>
- BOOST_ATTRIBUTE_NODISCARD error_code
- escape_impl(string_view input, character_set charset, Escaper escaper, output_string_ref output)
- {
- const char* it = input.data();
- const char* end = it + input.size();
- // The raw range is a range of contiguous characters that don't need escaping.
- // We only append the raw range once we find a character that needs escaping
- const char* raw_begin = it;
- while (it != end)
- {
- escape_sequence seq = escaper(*it);
- if (seq.is_escape())
- {
- // Dump what we already had
- output.append({raw_begin, it});
- // Output the escape sequence
- output.append(seq.data());
- // Advance
- ++it;
- // Update the start of the range that doesn't need escaping
- raw_begin = it;
- }
- else
- {
- // Advance with the charset function
- std::size_t char_size = detail::call_next_char(charset, it, end);
- if (char_size == 0u)
- return client_errc::invalid_encoding;
- it += char_size;
- }
- }
- // Dump the remaining of the string, if any
- output.append({raw_begin, end});
- // Done
- return error_code();
- }
- struct backslash_escaper
- {
- escape_sequence operator()(char input) const noexcept
- {
- switch (input)
- {
- case '\0': return {'\\', '0'};
- case '\n': return {'\\', 'n'};
- case '\r': return {'\\', 'r'};
- case '\\': return {'\\', '\\'};
- case '\'': return {'\\', '\''};
- case '"': return {'\\', '"'};
- case '\x1a': return {'\\', 'Z'}; // Ctrl+Z
- default: return escape_sequence(); // No escape
- }
- };
- };
- struct quote_escaper
- {
- char quot;
- quote_escaper(char q) noexcept : quot(q) {}
- escape_sequence operator()(char input) const noexcept
- {
- return input == quot ? escape_sequence(quot, quot) : escape_sequence();
- }
- };
- } // namespace detail
- } // namespace mysql
- } // namespace boost
- boost::mysql::error_code boost::mysql::detail::escape_string(
- string_view input,
- const format_options& opts,
- char escape_char,
- output_string_ref output
- )
- {
- return (escape_char == '`' || !opts.backslash_escapes)
- ? detail::escape_impl(input, opts.charset, quote_escaper(escape_char), output)
- : detail::escape_impl(input, opts.charset, backslash_escaper(), output);
- }
- #endif
|