Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-17 08:39:01

0001 //
0002 // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // A (possibly null) escape sequence of two characters. Used as the return value for escapers
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 // Escaper is a function object that takes a char and returns a
0041 // escape_sequence determining whether we should escape the char or not
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     // The raw range is a range of contiguous characters that don't need escaping.
0050     // We only append the raw range once we find a character that needs escaping
0051     const char* raw_begin = it;
0052     while (it != end)
0053     {
0054         escape_sequence seq = escaper(*it);
0055         if (seq.is_escape())
0056         {
0057             // Dump what we already had
0058             output.append({raw_begin, it});
0059 
0060             // Output the escape sequence
0061             output.append(seq.data());
0062 
0063             // Advance
0064             ++it;
0065 
0066             // Update the start of the range that doesn't need escaping
0067             raw_begin = it;
0068         }
0069         else
0070         {
0071             // Advance with the charset function
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     // Dump the remaining of the string, if any
0080     output.append({raw_begin, end});
0081 
0082     // Done
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'};    // Ctrl+Z
0099         default: return escape_sequence();  // No escape
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 }  // namespace detail
0117 }  // namespace mysql
0118 }  // namespace boost
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