diff --git a/libs/editor/changeset_wrapper.cpp b/libs/editor/changeset_wrapper.cpp index 44011d226..c6dcd78d0 100644 --- a/libs/editor/changeset_wrapper.cpp +++ b/libs/editor/changeset_wrapper.cpp @@ -243,14 +243,11 @@ void ChangesetWrapper::Modify(editor::XMLFeature node) void ChangesetWrapper::AddChangesetTag(std::string key, std::string value) { - value = strings::EscapeForXML(value); + // Truncate to 254 characters as OSM has a length limit of 255 + if (strings::Truncate(value, kMaximumOsmChars)) + value += "…"; - //OSM has a length limit of 255 characters - if (value.length() > kMaximumOsmChars) - { - LOG(LWARNING, ("value is too long for OSM 255 char limit: ", value)); - value = value.substr(0, kMaximumOsmChars - 3).append("..."); - } + value = strings::EscapeForXML(value); m_changesetComments.insert_or_assign(std::move(key), std::move(value)); } diff --git a/libs/indexer/editable_map_object.cpp b/libs/indexer/editable_map_object.cpp index 1389e31ef..90df34ca7 100644 --- a/libs/indexer/editable_map_object.cpp +++ b/libs/indexer/editable_map_object.cpp @@ -479,6 +479,9 @@ bool EditableMapObject::CheckHouseNumberWhenIsAddress() const // static bool EditableMapObject::ValidateFlats(string const & flats) { + if (strings::CountChar(flats) > kMaximumOsmChars) + return false; + for (auto it = strings::SimpleTokenizer(flats, ";"); it; ++it) { string_view token = *it; @@ -516,6 +519,9 @@ bool EditableMapObject::ValidatePhoneList(string const & phone) if (phone.empty()) return true; + if (strings::CountChar(phone) > kMaximumOsmChars) + return false; + auto constexpr kMaxNumberLen = 15; auto constexpr kMinNumberLen = 5; @@ -556,6 +562,9 @@ bool EditableMapObject::ValidateEmail(string const & email) if (email.empty()) return true; + if (strings::CountChar(email) > kMaximumOsmChars) + return false; + if (strings::IsASCIIString(email)) { static auto const s_emailRegex = regex(R"([^@\s]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$)"); @@ -589,6 +598,9 @@ bool EditableMapObject::ValidateLevel(string const & level) if (level.empty()) return true; + if (strings::CountChar(level) > kMaximumOsmChars) + return false; + if (level.front() == ';' || level.back() == ';' || level.find(";;") != std::string::npos) return false; @@ -633,6 +645,9 @@ bool EditableMapObject::ValidateName(string const & name) if (name.empty()) return true; + if (strings::CountChar(name) > kMaximumOsmChars) + return false; + static std::u32string_view constexpr excludedSymbols = U"^§><*=_±√•÷×¶"; using Iter = utf8::unchecked::iterator; diff --git a/libs/indexer/editable_map_object.hpp b/libs/indexer/editable_map_object.hpp index ffa2a8fe4..f54dbcb70 100644 --- a/libs/indexer/editable_map_object.hpp +++ b/libs/indexer/editable_map_object.hpp @@ -70,6 +70,7 @@ class EditableMapObject : public MapObject { public: static uint8_t constexpr kMaximumLevelsEditableByUsers = 50; + static int constexpr kMaximumOsmChars = 255; bool IsNameEditable() const; bool IsAddressEditable() const; diff --git a/libs/indexer/validate_and_format_contacts.cpp b/libs/indexer/validate_and_format_contacts.cpp index 063349bd6..08e9a3198 100644 --- a/libs/indexer/validate_and_format_contacts.cpp +++ b/libs/indexer/validate_and_format_contacts.cpp @@ -408,6 +408,10 @@ bool ValidateWebsite(string const & site) auto const startPos = GetProtocolNameLength(site); + // check lengt and leave room for addition of 'http://' + if (strings::CountChar(site) > (IsProtocolSpecified(site) ? kMaximumOsmChars : kMaximumOsmChars - 7)) + return false; + if (startPos >= site.size()) return false; @@ -429,6 +433,9 @@ bool ValidateFacebookPage(string const & page) if (page.empty()) return true; + if (strings::CountChar(page) > kMaximumOsmChars) + return false; + // Check if 'page' contains valid Facebook username or page name. // * length >= 5 // * no forbidden symbols in the string @@ -452,6 +459,9 @@ bool ValidateInstagramPage(string const & page) if (page.empty()) return true; + if (strings::CountChar(page) > kMaximumOsmChars) + return false; + // Rules are defined here: https://blog.jstassen.com/2016/03/code-regex-for-instagram-username-and-hashtags/ if (regex_match(page, s_instaRegex)) return true; @@ -468,6 +478,9 @@ bool ValidateTwitterPage(string const & page) if (page.empty()) return true; + if (strings::CountChar(page) > kMaximumOsmChars) + return false; + if (!ValidateWebsite(page)) return regex_match(page, s_twitterRegex); // Rules are defined here: https://stackoverflow.com/q/11361044 @@ -480,6 +493,9 @@ bool ValidateVkPage(string const & page) if (page.empty()) return true; + if (strings::CountChar(page) > kMaximumOsmChars) + return false; + { // Check that page contains valid username. Rules took here: https://vk.com/faq18038 // The page name must be between 5 and 32 characters. @@ -513,6 +529,9 @@ bool ValidateLinePage(string const & page) if (page.empty()) return true; + if (strings::CountChar(page) > kMaximumOsmChars) + return false; + { // Check that linePage contains valid page name. // Rules are defined here: https://help.line.me/line/?contentId=10009904 @@ -536,6 +555,9 @@ bool ValidateFediversePage(string const & page) if (page.empty()) return true; + if (strings::CountChar(page) > kMaximumOsmChars) + return false; + // Match @username@instance.name format if (regex_match(page, s_fediverseRegex)) return true; @@ -575,6 +597,9 @@ bool ValidateBlueskyPage(string const & page) if (page.empty()) return true; + if (strings::CountChar(page) > kMaximumOsmChars) + return false; + // Match {@?}{user/domain.name} format if (regex_match(page, s_blueskyRegex)) return true; diff --git a/libs/indexer/validate_and_format_contacts.hpp b/libs/indexer/validate_and_format_contacts.hpp index 29871e7c5..63b5737f5 100644 --- a/libs/indexer/validate_and_format_contacts.hpp +++ b/libs/indexer/validate_and_format_contacts.hpp @@ -6,6 +6,8 @@ namespace osm { +static int constexpr kMaximumOsmChars = 255; + std::string ValidateAndFormat_website(std::string const & v); std::string ValidateAndFormat_facebook(std::string const & v); std::string ValidateAndFormat_instagram(std::string const & v);