123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- /**
- * 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 <assert.h>
- #include <stdint.h>
- #include <string>
- #include <vector>
- #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 <typename T>
- struct non_numeric : std::enable_if<!std::is_arithmetic<T>::value> { };
- /**
- * Public interface for all the codecs. For API documentation, see README.md.
- */
- template <typename CodecImpl>
- 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 <typename Result> static Result encode(const uint8_t* binary, size_t binary_size);
- template <typename Result> static Result encode(const char* binary, size_t binary_size);
- template <typename Result = std::string, typename T = std::vector<uint8_t>>
- static Result encode(const T& binary);
- // Reused result container version. Resizes encoded_result before writing to it.
- template <typename Result>
- static void encode(Result& encoded_result, const uint8_t* binary, size_t binary_size);
- template <typename Result>
- static void encode(Result& encoded_result, const char* binary, size_t binary_size);
- template <typename Result, typename T, typename non_numeric<T>::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<typename T>
- 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<uint8_t>.
- static std::vector<uint8_t> decode(const char* encoded, size_t encoded_size);
- // static std::vector<uint8_t> decode(const T& encoded); -> provided by template below
- // Convenient version with templated result type.
- template <typename Result> static Result decode(const char* encoded, size_t encoded_size);
- template <typename Result = std::vector<uint8_t>, typename T = std::string>
- static Result decode(const T& encoded);
- // Reused result container version. Resizes binary_result before writing to it.
- template <typename Result>
- static void decode(Result& binary_result, const char* encoded, size_t encoded_size);
- template <typename Result, typename T, typename non_numeric<T>::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<typename T> static size_t decode(
- uint8_t* binary_result, size_t binary_buffer_size, const T& encoded);
- template<typename T> 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 <typename CodecImpl>
- inline std::string codec<CodecImpl>::encode(const uint8_t* binary, size_t binary_size)
- {
- return encode<std::string>(binary, binary_size);
- }
- template <typename CodecImpl>
- inline std::string codec<CodecImpl>::encode(const char* binary, size_t binary_size)
- {
- return encode<std::string>(reinterpret_cast<const uint8_t*>(binary), binary_size);
- }
- template <typename CodecImpl>
- template <typename Result>
- inline Result codec<CodecImpl>::encode(const uint8_t* binary, size_t binary_size)
- {
- Result encoded_result;
- encode(encoded_result, binary, binary_size);
- return encoded_result;
- }
- template <typename CodecImpl>
- template <typename Result>
- inline Result codec<CodecImpl>::encode(const char* binary, size_t binary_size)
- {
- return encode<Result>(reinterpret_cast<const uint8_t*>(binary), binary_size);
- }
- template <typename CodecImpl>
- template <typename Result, typename T>
- inline Result codec<CodecImpl>::encode(const T& binary)
- {
- return encode<Result>(data::uchar_data(binary), data::size(binary));
- }
- template <typename CodecImpl>
- template <typename Result>
- inline void codec<CodecImpl>::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 <typename CodecImpl>
- template <typename Result>
- inline void codec<CodecImpl>::encode(
- Result& encoded_result, const char* binary, size_t binary_size)
- {
- encode(encoded_result, reinterpret_cast<const uint8_t*>(binary), binary_size);
- }
- template <typename CodecImpl>
- template <typename Result, typename T, typename non_numeric<T>::type*>
- inline void codec<CodecImpl>::encode(Result& encoded_result, const T& binary)
- {
- encode(encoded_result, data::uchar_data(binary), data::size(binary));
- }
- template <typename CodecImpl>
- inline size_t codec<CodecImpl>::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 <typename CodecImpl>
- inline size_t codec<CodecImpl>::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<const uint8_t*>(binary), binary_size);
- }
- template <typename CodecImpl>
- template <typename T>
- inline size_t codec<CodecImpl>::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 <typename CodecImpl>
- inline constexpr size_t codec<CodecImpl>::encoded_size(size_t binary_size) noexcept
- {
- return CodecImpl::encoded_size(binary_size);
- }
- //
- // Decoding
- template <typename CodecImpl>
- inline std::vector<uint8_t> codec<CodecImpl>::decode(const char* encoded, size_t encoded_size)
- {
- return decode<std::vector<uint8_t>>(encoded, encoded_size);
- }
- template <typename CodecImpl>
- template <typename Result>
- inline Result codec<CodecImpl>::decode(const char* encoded, size_t encoded_size)
- {
- Result result;
- decode(result, encoded, encoded_size);
- return result;
- }
- template <typename CodecImpl>
- template <typename Result, typename T>
- inline Result codec<CodecImpl>::decode(const T& encoded)
- {
- return decode<Result>(data::char_data(encoded), data::size(encoded));
- }
- template <typename CodecImpl>
- template <typename Result>
- inline void codec<CodecImpl>::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 <typename CodecImpl>
- template <typename Result, typename T, typename non_numeric<T>::type*>
- inline void codec<CodecImpl>::decode(Result& binary_result, const T& encoded)
- {
- decode(binary_result, data::char_data(encoded), data::size(encoded));
- }
- template <typename CodecImpl>
- inline size_t codec<CodecImpl>::decode(
- uint8_t* binary_result, size_t binary_buffer_size,
- const char* encoded, size_t encoded_size)
- {
- return decode(reinterpret_cast<char*>(binary_result), binary_buffer_size, encoded, encoded_size);
- }
- template <typename CodecImpl>
- inline size_t codec<CodecImpl>::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 <typename CodecImpl>
- template <typename T>
- inline size_t codec<CodecImpl>::decode(
- uint8_t* binary_result, size_t binary_buffer_size, const T& encoded)
- {
- return decode(reinterpret_cast<char*>(binary_result), binary_buffer_size, encoded);
- }
- template <typename CodecImpl>
- template <typename T>
- inline size_t codec<CodecImpl>::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 <typename CodecImpl>
- inline constexpr size_t codec<CodecImpl>::decoded_max_size(size_t encoded_size) noexcept
- {
- return CodecImpl::decoded_max_size(encoded_size);
- }
- } // namespace detail
- } // namespace cppcodec
- #endif
|