// Copyright (c) 2023, 2024, Oracle and/or its affiliates. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License, version 2.0, // as published by the Free Software Foundation. // // This program is designed to work with certain software (including // but not limited to OpenSSL) that is licensed under separate terms, // as designated in a particular file or component or in included license // documentation. The authors of MySQL hereby grant you an additional // permission to link the program and your derivative works with the // separately licensed software that they have either included with // the program or referenced in the documentation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License, version 2.0, for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "mysql/gtid/tag.h" #include #include #include #include #include "mysql/gtid/internal/parsing_helpers.h" #include "mysql/serialization/primitive_type_codec.h" using namespace std; using Field_size = mysql::serialization::Field_size; template using Primitive_type_codec = mysql::serialization::Primitive_type_codec; template using Byte_count_helper = mysql::serialization::Byte_count_helper; namespace mysql::gtid { void Tag::replace(const char *text, std::size_t len) { m_data.clear(); m_data.reserve(len); for (size_t result_pos = 0; result_pos < len; ++result_pos) { m_data.push_back(internal::tolower(text[result_pos])); } } Tag::Tag(const std::string &text) { std::ignore = from_string(text); } std::string Tag::to_string() const { return m_data; } std::size_t Tag::to_string(char *out) const { if (is_empty()) { return 0; } memcpy(out, m_data.data(), m_data.length()); out[m_data.length()] = '\0'; return m_data.length(); } std::size_t Tag::encode_tag(unsigned char *buf, const Gtid_format >id_format) const { if (gtid_format == Gtid_format::untagged) { assert(is_empty()); return 0; } return Primitive_type_codec::write_bytes(buf, m_data); } std::size_t Tag::decode_tag(const unsigned char *buf, std::size_t buf_len, const Gtid_format >id_format) { m_data.clear(); std::size_t bytes_read = 0; if (gtid_format == Gtid_format::untagged) { return bytes_read; } Tag unverified_tag; bytes_read = Primitive_type_codec::read_bytes( buf, buf_len, unverified_tag.m_data); auto characters_valid = from_cstring(unverified_tag.m_data.data()); if (characters_valid == unverified_tag.get_length()) { return bytes_read; } return 0; } size_t Tag::get_encoded_length(const Gtid_format >id_format) const { if (gtid_format == Gtid_format::tagged) { return Byte_count_helper::count_write_bytes(m_data); } // untagged GTIDs assert(m_data.length() == 0); return 0; } std::size_t Tag::get_length() const { return m_data.length(); } bool Tag::is_valid_end_char(const char &character) { return character == gtid_separator || character == '\0' || character == gtid_set_separator; } size_t Tag::from_string(const std::string &text) { return from_cstring(text.c_str()); } bool Tag::is_character_valid(const char &character, std::size_t pos) { return (internal::isalpha(character) || character == '_' || (internal::isdigit(character) && pos > 0)); } size_t Tag::from_cstring(const char *text) { m_data.clear(); size_t result_len = 0, pos = 0; while (internal::isspace(text[pos])) { ++pos; } size_t start_pos = pos; while (is_character_valid(text[pos], result_len) && result_len < tag_max_length) { ++result_len; ++pos; } while (internal::isspace(text[pos])) { ++pos; } if (is_valid_end_char(text[pos]) == false) { // invalid tag specification, return 0 return 0; } replace(text + start_pos, result_len); return pos; } bool Tag::operator==(const Tag &other) const { return m_data == other.m_data; } bool Tag::operator!=(const Tag &other) const { return !(*this == other); } Tag::Tag(const Tag_plain &tag) { m_data = ""; if (tag.is_defined()) { m_data.assign(reinterpret_cast(tag.data())); } } size_t Tag::Hash::operator()(const Tag &arg) const { return std::hash{}(arg.m_data); } } // namespace mysql::gtid