/** * Copyright (C) 2015 Topology LP * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef CPPCODEC_DETAIL_CODEC #define CPPCODEC_DETAIL_CODEC #include #include #include #include #include "../data/access.hpp" #include "../data/raw_result_buffer.hpp" namespace cppcodec { namespace detail { // SFINAE: Templates sometimes beat sensible overloads - make sure we don't call the wrong one. template struct non_numeric : std::enable_if::value> { }; /** * Public interface for all the codecs. For API documentation, see README.md. */ template class codec { public: // // Encoding // Convenient version, returns an std::string. static std::string encode(const uint8_t* binary, size_t binary_size); static std::string encode(const char* binary, size_t binary_size); // static std::string encode(const T& binary); -> provided by template below // Convenient version with templated result type. template static Result encode(const uint8_t* binary, size_t binary_size); template static Result encode(const char* binary, size_t binary_size); template > static Result encode(const T& binary); // Reused result container version. Resizes encoded_result before writing to it. template static void encode(Result& encoded_result, const uint8_t* binary, size_t binary_size); template static void encode(Result& encoded_result, const char* binary, size_t binary_size); template ::type* = nullptr> static void encode(Result& encoded_result, const T& binary); // Raw pointer output, assumes pre-allocated memory with size > encoded_size(binary_size). static size_t encode( char* encoded_result, size_t encoded_buffer_size, const uint8_t* binary, size_t binary_size) noexcept; static size_t encode( char* encoded_result, size_t encoded_buffer_size, const char* binary, size_t binary_size) noexcept; template static size_t encode( char* encoded_result, size_t encoded_buffer_size, const T& binary) noexcept; // Calculate the exact length of the encoded string based on binary size. static constexpr size_t encoded_size(size_t binary_size) noexcept; // // Decoding // Convenient version, returns an std::vector. static std::vector decode(const char* encoded, size_t encoded_size); // static std::vector decode(const T& encoded); -> provided by template below // Convenient version with templated result type. template static Result decode(const char* encoded, size_t encoded_size); template , typename T = std::string> static Result decode(const T& encoded); // Reused result container version. Resizes binary_result before writing to it. template static void decode(Result& binary_result, const char* encoded, size_t encoded_size); template ::type* = nullptr> static void decode(Result& binary_result, const T& encoded); // Raw pointer output, assumes pre-allocated memory with size > decoded_max_size(encoded_size). static size_t decode( uint8_t* binary_result, size_t binary_buffer_size, const char* encoded, size_t encoded_size); static size_t decode( char* binary_result, size_t binary_buffer_size, const char* encoded, size_t encoded_size); template static size_t decode( uint8_t* binary_result, size_t binary_buffer_size, const T& encoded); template static size_t decode( char* binary_result, size_t binary_buffer_size, const T& encoded); // Calculate the maximum size of the decoded binary buffer based on the encoded string length. static constexpr size_t decoded_max_size(size_t encoded_size) noexcept; }; // // Inline definitions of the above functions, using CRTP to call into CodecImpl // // // Encoding template inline std::string codec::encode(const uint8_t* binary, size_t binary_size) { return encode(binary, binary_size); } template inline std::string codec::encode(const char* binary, size_t binary_size) { return encode(reinterpret_cast(binary), binary_size); } template template inline Result codec::encode(const uint8_t* binary, size_t binary_size) { Result encoded_result; encode(encoded_result, binary, binary_size); return encoded_result; } template template inline Result codec::encode(const char* binary, size_t binary_size) { return encode(reinterpret_cast(binary), binary_size); } template template inline Result codec::encode(const T& binary) { return encode(data::uchar_data(binary), data::size(binary)); } template template inline void codec::encode( Result& encoded_result, const uint8_t* binary, size_t binary_size) { // This overload is where we reserve buffer capacity and call into CodecImpl. size_t encoded_buffer_size = encoded_size(binary_size); auto state = data::create_state(encoded_result, data::specific_t()); data::init(encoded_result, state, encoded_buffer_size); CodecImpl::encode(encoded_result, state, binary, binary_size); data::finish(encoded_result, state); assert(data::size(encoded_result) == encoded_buffer_size); } template template inline void codec::encode( Result& encoded_result, const char* binary, size_t binary_size) { encode(encoded_result, reinterpret_cast(binary), binary_size); } template template ::type*> inline void codec::encode(Result& encoded_result, const T& binary) { encode(encoded_result, data::uchar_data(binary), data::size(binary)); } template inline size_t codec::encode( char* encoded_result, size_t encoded_buffer_size, const uint8_t* binary, size_t binary_size) noexcept { // This overload is where we wrap the result pointer & size. data::raw_result_buffer encoded(encoded_result, encoded_buffer_size); encode(encoded, binary, binary_size); size_t encoded_size = data::size(encoded); if (encoded_size < encoded_buffer_size) { encoded_result[encoded_size] = '\0'; } return encoded_size; } template inline size_t codec::encode( char* encoded_result, size_t encoded_buffer_size, const char* binary, size_t binary_size) noexcept { // This overload is where we wrap the result pointer & size. return encode(encoded_result, encoded_buffer_size, reinterpret_cast(binary), binary_size); } template template inline size_t codec::encode( char* encoded_result, size_t encoded_buffer_size, const T& binary) noexcept { return encode(encoded_result, encoded_buffer_size, data::uchar_data(binary), data::size(binary)); } template inline constexpr size_t codec::encoded_size(size_t binary_size) noexcept { return CodecImpl::encoded_size(binary_size); } // // Decoding template inline std::vector codec::decode(const char* encoded, size_t encoded_size) { return decode>(encoded, encoded_size); } template template inline Result codec::decode(const char* encoded, size_t encoded_size) { Result result; decode(result, encoded, encoded_size); return result; } template template inline Result codec::decode(const T& encoded) { return decode(data::char_data(encoded), data::size(encoded)); } template template inline void codec::decode(Result& binary_result, const char* encoded, size_t encoded_size) { // This overload is where we reserve buffer capacity and call into CodecImpl. size_t binary_buffer_size = decoded_max_size(encoded_size); auto state = data::create_state(binary_result, data::specific_t()); data::init(binary_result, state, binary_buffer_size); CodecImpl::decode(binary_result, state, encoded, encoded_size); data::finish(binary_result, state); assert(data::size(binary_result) <= binary_buffer_size); } template template ::type*> inline void codec::decode(Result& binary_result, const T& encoded) { decode(binary_result, data::char_data(encoded), data::size(encoded)); } template inline size_t codec::decode( uint8_t* binary_result, size_t binary_buffer_size, const char* encoded, size_t encoded_size) { return decode(reinterpret_cast(binary_result), binary_buffer_size, encoded, encoded_size); } template inline size_t codec::decode( char* binary_result, size_t binary_buffer_size, const char* encoded, size_t encoded_size) { // This overload is where we wrap the result pointer & size. data::raw_result_buffer binary(binary_result, binary_buffer_size); decode(binary, encoded, encoded_size); return data::size(binary); } template template inline size_t codec::decode( uint8_t* binary_result, size_t binary_buffer_size, const T& encoded) { return decode(reinterpret_cast(binary_result), binary_buffer_size, encoded); } template template inline size_t codec::decode(char* binary_result, size_t binary_buffer_size, const T& encoded) { return decode(binary_result, binary_buffer_size, data::char_data(encoded), data::size(encoded)); } template inline constexpr size_t codec::decoded_max_size(size_t encoded_size) noexcept { return CodecImpl::decoded_max_size(encoded_size); } } // namespace detail } // namespace cppcodec #endif