// Copyright 2013 Daniel Parker // Distributed under the Boost license, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See https://github.com/danielaparker/jsoncons for latest version #ifndef JSONCONS_BYTE_STRING_HPP #define JSONCONS_BYTE_STRING_HPP #include #include #include #include #include // std::memcmp #include // std::allocator #include #include #include // std::setw #include #include // std::move #include #include #include #include namespace jsoncons { // Algorithms namespace detail { template typename std::enable_if::value_type,uint8_t>::value,size_t>::type encode_base64_generic(InputIt first, InputIt last, const char alphabet[65], Container& result) { std::size_t count = 0; unsigned char a3[3]; unsigned char a4[4]; unsigned char fill = alphabet[64]; int i = 0; int j = 0; while (first != last) { a3[i++] = *first++; if (i == 3) { a4[0] = (a3[0] & 0xfc) >> 2; a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); a4[3] = a3[2] & 0x3f; for (i = 0; i < 4; i++) { result.push_back(alphabet[a4[i]]); ++count; } i = 0; } } if (i > 0) { for (j = i; j < 3; ++j) { a3[j] = 0; } a4[0] = (a3[0] & 0xfc) >> 2; a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); for (j = 0; j < i + 1; ++j) { result.push_back(alphabet[a4[j]]); ++count; } if (fill != 0) { while (i++ < 3) { result.push_back(fill); ++count; } } } return count; } template typename std::enable_if::value,decode_result>::type decode_base64_generic(InputIt first, InputIt last, const uint8_t reverse_alphabet[256], F f, Container& result) { uint8_t a4[4], a3[3]; uint8_t i = 0; uint8_t j = 0; while (first != last && *first != '=') { if (!f(*first)) { return decode_result{first, conv_errc::conversion_failed}; } a4[i++] = *first++; if (i == 4) { for (i = 0; i < 4; ++i) { a4[i] = reverse_alphabet[a4[i]]; } a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; for (i = 0; i < 3; i++) { result.push_back(a3[i]); } i = 0; } } if (i > 0) { for (j = 0; j < i; ++j) { a4[j] = reverse_alphabet[a4[j]]; } a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); for (j = 0; j < i - 1; ++j) { result.push_back(a3[j]); } } return decode_result{last, conv_errc::success}; } } // namespace detail template typename std::enable_if::value_type,uint8_t>::value,size_t>::type encode_base16(InputIt first, InputIt last, Container& result) { static constexpr char characters[] = "0123456789ABCDEF"; for (auto it = first; it != last; ++it) { uint8_t c = *it; result.push_back(characters[c >> 4]); result.push_back(characters[c & 0xf]); } return (last-first)*2; } template typename std::enable_if::value_type,uint8_t>::value,size_t>::type encode_base64url(InputIt first, InputIt last, Container& result) { static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-_" "\0"; return detail::encode_base64_generic(first, last, alphabet, result); } template typename std::enable_if::value_type,uint8_t>::value,size_t>::type encode_base64(InputIt first, InputIt last, Container& result) { static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/" "="; return detail::encode_base64_generic(first, last, alphabet, result); } template bool is_base64(Char c) { return (c >= 0 && c < 128) && (isalnum((int)c) || c == '+' || c == '/'); } template bool is_base64url(Char c) { return (c >= 0 && c < 128) && (isalnum((int)c) || c == '-' || c == '_'); } inline static bool is_base64url(int c) { return isalnum(c) || c == '-' || c == '_'; } // decode template typename std::enable_if::value,decode_result>::type decode_base64url(InputIt first, InputIt last, Container& result) { static constexpr uint8_t reverse_alphabet[256] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 63, 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; auto retval = jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet, is_base64url::value_type>, result); return retval.ec == conv_errc::success ? retval : decode_result{retval.it, conv_errc::not_base64url}; } template typename std::enable_if::value,decode_result>::type decode_base64(InputIt first, InputIt last, Container& result) { static constexpr uint8_t reverse_alphabet[256] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; auto retval = jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet, is_base64::value_type>, result); return retval.ec == conv_errc::success ? retval : decode_result{retval.it, conv_errc::not_base64}; } template typename std::enable_if::value,decode_result>::type decode_base16(InputIt first, InputIt last, Container& result) { std::size_t len = std::distance(first,last); if (len & 1) { return decode_result{first, conv_errc::not_base16}; } InputIt it = first; while (it != last) { uint8_t val; auto a = *it++; if (a >= '0' && a <= '9') { val = (a - '0') << 4; } else if ((a | 0x20) >= 'a' && (a | 0x20) <= 'f') { val = ((a | 0x20) - 'a' + 10) << 4; } else { return decode_result{first, conv_errc::not_base16}; } auto b = *it++; if (b >= '0' && b <= '9') { val |= (b - '0'); } else if ((b | 0x20) >= 'a' && (b | 0x20) <= 'f') { val |= ((b | 0x20) - 'a' + 10); } else { return decode_result{first, conv_errc::not_base16}; } result.push_back(val); } return decode_result{last, conv_errc::success}; } struct byte_traits { using char_type = uint8_t; static constexpr int eof() { return std::char_traits::eof(); } static int compare(const char_type* s1, const char_type* s2, std::size_t count) noexcept { return std::memcmp(s1,s2,count); } }; // basic_byte_string template class basic_byte_string; // byte_string_view class byte_string_view { const uint8_t* data_; std::size_t size_; public: using traits_type = byte_traits; using const_iterator = const uint8_t*; using iterator = const_iterator; using size_type = std::size_t; using value_type = uint8_t; using reference = uint8_t&; using const_reference = const uint8_t&; using difference_type = std::ptrdiff_t; using pointer = uint8_t*; using const_pointer = const uint8_t*; constexpr byte_string_view() noexcept : data_(nullptr), size_(0) { } constexpr byte_string_view(const uint8_t* data, std::size_t length) noexcept : data_(data), size_(length) { } template constexpr explicit byte_string_view(const Container& cont, typename std::enable_if::value,int>::type = 0) : data_(reinterpret_cast(cont.data())), size_(cont.size()) { } template constexpr byte_string_view(const basic_byte_string& bytes); constexpr byte_string_view(const byte_string_view&) noexcept = default; JSONCONS_CPP14_CONSTEXPR byte_string_view(byte_string_view&& other) noexcept : data_(nullptr), size_(0) { const_pointer temp_data = data_; data_ = other.data_; other.data_ = temp_data; size_type temp_size = size_; size_ = other.size_; other.size_ = temp_size; } byte_string_view& operator=(const byte_string_view&) = default; byte_string_view& operator=(byte_string_view&& other) noexcept { std::swap(data_, other.data_); std::swap(size_, other.size_); return *this; } constexpr const uint8_t* data() const noexcept { return data_; } #if !defined(JSONCONS_NO_DEPRECATED) JSONCONS_DEPRECATED_MSG("Instead, use size()") std::size_t length() const { return size_; } #endif constexpr size_t size() const noexcept { return size_; } // iterator support constexpr const_iterator begin() const noexcept { return data_; } constexpr const_iterator end() const noexcept { return data_ + size_; } constexpr const_iterator cbegin() const noexcept { return data_; } constexpr const_iterator cend() const noexcept { return data_ + size_; } constexpr uint8_t operator[](size_type pos) const { return data_[pos]; } JSONCONS_CPP14_CONSTEXPR byte_string_view substr(size_type pos) const { if (pos > size_) { JSONCONS_THROW(std::out_of_range("pos exceeds size")); } std::size_t n = size_ - pos; return byte_string_view(data_ + pos, n); } byte_string_view substr(size_type pos, size_type n) const { if (pos > size_) { JSONCONS_THROW(std::out_of_range("pos exceeds size")); } if (pos + n > size_) { n = size_ - pos; } return byte_string_view(data_ + pos, n); } int compare(const byte_string_view& s) const noexcept { const int rc = traits_type::compare(data_, s.data(), (std::min)(size_, s.size())); return rc != 0 ? rc : (size_ == s.size() ? 0 : size_ < s.size() ? -1 : 1); } template int compare(const basic_byte_string& s) const noexcept { const int rc = traits_type::compare(data_, s.data(), (std::min)(size_, s.size())); return rc != 0 ? rc : (size_ == s.size() ? 0 : size_ < s.size() ? -1 : 1); } template friend std::basic_ostream& operator<<(std::basic_ostream& os, const byte_string_view& bstr) { std::basic_ostringstream ss; ss.flags(std::ios::hex); ss.fill('0'); bool first = true; for (auto b : bstr) { if (first) { first = false; } else { ss << ','; } ss << std::setw(2) << static_cast(b); } os << ss.str(); return os; } }; // basic_byte_string template > class basic_byte_string { using byte_allocator_type = typename std::allocator_traits:: template rebind_alloc; std::vector data_; public: using traits_type = byte_traits; using allocator_type = byte_allocator_type; using value_type = typename std::vector::value_type; using size_type = typename std::vector::size_type; using difference_type = typename std::vector::difference_type; using reference = typename std::vector::reference; using const_reference = typename std::vector::const_reference; using pointer = typename std::vector::pointer; using const_pointer = typename std::vector::const_pointer; using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; basic_byte_string() = default; explicit basic_byte_string(const Allocator& alloc) : data_(alloc) { } basic_byte_string(std::initializer_list init) : data_(std::move(init)) { } basic_byte_string(std::initializer_list init, const Allocator& alloc) : data_(std::move(init), alloc) { } explicit basic_byte_string(const byte_string_view& v) : data_(v.begin(),v.end()) { } basic_byte_string(const basic_byte_string& v) : data_(v.data_) { } basic_byte_string(basic_byte_string&& v) noexcept : data_(std::move(v.data_)) { } basic_byte_string(const byte_string_view& v, const Allocator& alloc) : data_(v.begin(),v.end(),alloc) { } basic_byte_string(const uint8_t* data, std::size_t length, const Allocator& alloc = Allocator()) : data_(data, data+length,alloc) { } Allocator get_allocator() const { return data_.get_allocator(); } basic_byte_string& operator=(const basic_byte_string& s) = default; basic_byte_string& operator=(basic_byte_string&& other) noexcept { data_.swap(other.data_); return *this; } void reserve(std::size_t new_cap) { data_.reserve(new_cap); } void push_back(uint8_t b) { data_.push_back(b); } void assign(const uint8_t* s, std::size_t count) { data_.clear(); data_.insert(s, s+count); } void append(const uint8_t* s, std::size_t count) { data_.insert(s, s+count); } void clear() { data_.clear(); } uint8_t operator[](size_type pos) const { return data_[pos]; } // iterator support iterator begin() noexcept { return data_.begin(); } iterator end() noexcept { return data_.end(); } const_iterator begin() const noexcept { return data_.begin(); } const_iterator end() const noexcept { return data_.end(); } uint8_t* data() { return data_.data(); } const uint8_t* data() const { return data_.data(); } std::size_t size() const { return data_.size(); } #if !defined(JSONCONS_NO_DEPRECATED) JSONCONS_DEPRECATED_MSG("Instead, use size()") std::size_t length() const { return data_.size(); } #endif int compare(const byte_string_view& s) const noexcept { const int rc = traits_type::compare(data(), s.data(), (std::min)(size(), s.size())); return rc != 0 ? rc : (size() == s.size() ? 0 : size() < s.size() ? -1 : 1); } int compare(const basic_byte_string& s) const noexcept { const int rc = traits_type::compare(data(), s.data(), (std::min)(size(), s.size())); return rc != 0 ? rc : (size() == s.size() ? 0 : size() < s.size() ? -1 : 1); } template friend std::basic_ostream& operator<<(std::basic_ostream& os, const basic_byte_string& o) { os << byte_string_view(o); return os; } }; template constexpr byte_string_view::byte_string_view(const basic_byte_string& bytes) : data_(bytes.data()), size_(bytes.size()) { } // == inline bool operator==(const byte_string_view& lhs, const byte_string_view& rhs) noexcept { return lhs.compare(rhs) == 0; } template bool operator==(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept { return lhs.compare(rhs) == 0; } template bool operator==(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept { return rhs.compare(lhs) == 0; } template bool operator==(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept { return rhs.compare(lhs) == 0; } // != inline bool operator!=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept { return lhs.compare(rhs) != 0; } template bool operator!=(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept { return lhs.compare(rhs) != 0; } template bool operator!=(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept { return rhs.compare(lhs) != 0; } template bool operator!=(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept { return rhs.compare(lhs) != 0; } // <= inline bool operator<=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept { return lhs.compare(rhs) <= 0; } template bool operator<=(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept { return lhs.compare(rhs) <= 0; } template bool operator<=(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept { return rhs.compare(lhs) >= 0; } template bool operator<=(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept { return rhs.compare(lhs) >= 0; } // < inline bool operator<(const byte_string_view& lhs, const byte_string_view& rhs) noexcept { return lhs.compare(rhs) < 0; } template bool operator<(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept { return lhs.compare(rhs) < 0; } template bool operator<(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept { return rhs.compare(lhs) > 0; } template bool operator<(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept { return rhs.compare(lhs) > 0; } // >= inline bool operator>=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept { return lhs.compare(rhs) >= 0; } template bool operator>=(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept { return lhs.compare(rhs) >= 0; } template bool operator>=(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept { return rhs.compare(lhs) <= 0; } template bool operator>=(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept { return rhs.compare(lhs) <= 0; } // > inline bool operator>(const byte_string_view& lhs, const byte_string_view& rhs) noexcept { return lhs.compare(rhs) > 0; } template bool operator>(const byte_string_view& lhs, const basic_byte_string& rhs) noexcept { return lhs.compare(rhs) > 0; } template bool operator>(const basic_byte_string& lhs, const byte_string_view& rhs) noexcept { return rhs.compare(lhs) < 0; } template bool operator>(const basic_byte_string& lhs, const basic_byte_string& rhs) noexcept { return rhs.compare(lhs) < 0; } using byte_string = basic_byte_string>; namespace type_traits { template struct is_basic_byte_string : std::false_type {}; template struct is_basic_byte_string> : std::true_type {}; } // namespace type_traits } // namespace jsoncons #endif