/* Deprecated representation for raw, binary data. * * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/binarystring instead. * * Copyright (c) 2000-2022, Jeroen T. Vermeulen. * * See COPYING for copyright license. If you did not receive a file called * COPYING with this source code, please notify the distributor of this * mistake, or contact the author. */ #ifndef PQXX_H_BINARYSTRING #define PQXX_H_BINARYSTRING #if !defined(PQXX_HEADER_PRE) # error "Include libpqxx headers as , not ." #endif #include #include #include #include "pqxx/result.hxx" #include "pqxx/strconv.hxx" namespace pqxx { class binarystring; template<> struct string_traits; /// Binary data corresponding to PostgreSQL's "BYTEA" binary-string type. /** @ingroup escaping-functions * @deprecated Use @c std::basic_string and * @c std::basic_string_view for binary data. In C++20 or better, * any @c contiguous_range of @c std::byte will do. * * This class represents a binary string as stored in a field of type @c bytea. * * Internally a binarystring is zero-terminated, but it may also contain null * bytes, they're just like any other byte value. So don't assume that it's * safe to treat the contents as a C-style string. * * The binarystring retains its value even if the result it was obtained from * is destroyed, but it cannot be copied or assigned. * * \relatesalso transaction_base::quote_raw * * To include a @c binarystring value in an SQL query, escape and quote it * using the transaction's @c quote_raw function. * * @warning This class is implemented as a reference-counting smart pointer. * Copying, swapping, and destroying binarystring objects that refer to the * same underlying data block is not thread-safe. If you wish to pass * binarystrings around between threads, make sure that each of these * operations is protected against concurrency with similar operations on the * same object, or other objects pointing to the same data block. */ class PQXX_LIBEXPORT binarystring { public: using char_type = unsigned char; using value_type = std::char_traits::char_type; using size_type = std::size_t; using difference_type = long; using const_reference = value_type const &; using const_pointer = value_type const *; using const_iterator = const_pointer; using const_reverse_iterator = std::reverse_iterator; [[deprecated("Use std::byte for binary data.")]] binarystring( binarystring const &) = default; /// Read and unescape bytea field. /** The field will be zero-terminated, even if the original bytea field * isn't. * @param F the field to read; must be a bytea field */ [[deprecated("Use std::byte for binary data.")]] explicit binarystring( field const &); /// Copy binary data from std::string_view on binary data. /** This is inefficient in that it copies the data to a buffer allocated on * the heap. */ [[deprecated("Use std::byte for binary data.")]] explicit binarystring( std::string_view); /// Copy binary data of given length straight out of memory. [[deprecated("Use std::byte for binary data.")]] binarystring( void const *, std::size_t); /// Efficiently wrap a buffer of binary data in a @c binarystring. [[deprecated("Use std::byte for binary data.")]] binarystring( std::shared_ptr ptr, size_type size) : m_buf{std::move(ptr)}, m_size{size} {} /// Size of converted string in bytes. [[nodiscard]] size_type size() const noexcept { return m_size; } /// Size of converted string in bytes. [[nodiscard]] size_type length() const noexcept { return size(); } [[nodiscard]] bool empty() const noexcept { return size() == 0; } [[nodiscard]] const_iterator begin() const noexcept { return data(); } [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); } [[nodiscard]] const_iterator end() const noexcept { return data() + m_size; } [[nodiscard]] const_iterator cend() const noexcept { return end(); } [[nodiscard]] const_reference front() const noexcept { return *begin(); } [[nodiscard]] const_reference back() const noexcept { return *(data() + m_size - 1); } [[nodiscard]] const_reverse_iterator rbegin() const { return const_reverse_iterator{end()}; } [[nodiscard]] const_reverse_iterator crbegin() const { return rbegin(); } [[nodiscard]] const_reverse_iterator rend() const { return const_reverse_iterator{begin()}; } [[nodiscard]] const_reverse_iterator crend() const { return rend(); } /// Unescaped field contents. [[nodiscard]] value_type const *data() const noexcept { return m_buf.get(); } [[nodiscard]] const_reference operator[](size_type i) const noexcept { return data()[i]; } [[nodiscard]] PQXX_PURE bool operator==(binarystring const &) const noexcept; [[nodiscard]] bool operator!=(binarystring const &rhs) const noexcept { return not operator==(rhs); } binarystring &operator=(binarystring const &); /// Index contained string, checking for valid index. const_reference at(size_type) const; /// Swap contents with other binarystring. void swap(binarystring &); /// Raw character buffer (no terminating zero is added). /** @warning No terminating zero is added! If the binary data did not end in * a null character, you will not find one here. */ [[nodiscard]] char const *get() const noexcept { return reinterpret_cast(m_buf.get()); } /// Read contents as a std::string_view. [[nodiscard]] std::string_view view() const noexcept { return std::string_view(get(), size()); } /// Read as regular C++ string (may include null characters). /** This creates and returns a new string object. Don't call this * repeatedly; retrieve your string once and keep it in a local variable. * Also, do not expect to be able to compare the string's address to that of * an earlier invocation. */ [[nodiscard]] std::string str() const; /// Access data as a pointer to @c std::byte. [[nodiscard]] std::byte const *bytes() const { return reinterpret_cast(get()); } /// Read data as a @c std::basic_string_view. [[nodiscard]] std::basic_string_view bytes_view() const { return std::basic_string_view{bytes(), size()}; } private: std::shared_ptr m_buf; size_type m_size{0}; }; template<> struct nullness : no_null {}; /// String conversion traits for @c binarystring. /** Defines the conversions between a @c binarystring and its PostgreSQL * textual format, for communication with the database. * * These conversions rely on the "hex" format which was introduced in * PostgreSQL 9.0. Both your libpq and the server must be recent enough to * speak this format. */ template<> struct string_traits { static std::size_t size_buffer(binarystring const &value) noexcept { return internal::size_esc_bin(std::size(value)); } static zview to_buf(char *begin, char *end, binarystring const &value) { return generic_to_buf(begin, end, value); } static char *into_buf(char *begin, char *end, binarystring const &value) { auto const budget{size_buffer(value)}; if (internal::cmp_less(end - begin, budget)) throw conversion_overrun{ "Not enough buffer space to escape binary data."}; std::string_view text{value.view()}; internal::esc_bin(binary_cast(text), begin); return begin + budget; } static binarystring from_string(std::string_view text) { auto const size{pqxx::internal::size_unesc_bin(std::size(text))}; std::shared_ptr buf{ new unsigned char[size], [](unsigned char const *x) { delete[] x; }}; pqxx::internal::unesc_bin(text, reinterpret_cast(buf.get())); #include "pqxx/internal/ignore-deprecated-pre.hxx" return binarystring{std::move(buf), size}; #include "pqxx/internal/ignore-deprecated-post.hxx" } }; } // namespace pqxx #endif