// https://tools.ietf.org/html/rfc6455#section-4.1 // "The HTTP version MUST be at least 1.1." static inline bool headerHasValidHTTPVersion(StringView httpStatusLine) { const char* httpVersionStaticPreambleLiteral = "HTTP/"; StringView httpVersionStaticPreamble(reinterpret_cast<const LChar*>(httpVersionStaticPreambleLiteral), strlen(httpVersionStaticPreambleLiteral)); if (!httpStatusLine.startsWith(httpVersionStaticPreamble)) return false; // Check that there is a version number which should be at least three characters after "HTTP/" unsigned preambleLength = httpVersionStaticPreamble.length(); if (httpStatusLine.length() < preambleLength + 3) return false; auto dotPosition = httpStatusLine.find('.', preambleLength); if (dotPosition == notFound) return false; StringView majorVersionView = httpStatusLine.substring(preambleLength, dotPosition - preambleLength); bool isValid; int majorVersion = majorVersionView.toIntStrict(isValid); if (!isValid) return false; unsigned minorVersionLength; unsigned charactersLeftAfterDotPosition = httpStatusLine.length() - dotPosition; for (minorVersionLength = 1; minorVersionLength < charactersLeftAfterDotPosition; minorVersionLength++) { if (!isASCIIDigit(httpStatusLine[dotPosition + minorVersionLength])) break; } int minorVersion = (httpStatusLine.substring(dotPosition + 1, minorVersionLength)).toIntStrict(isValid); if (!isValid) return false; return (majorVersion >= 1 && minorVersion >= 1) || majorVersion >= 2; }
// TODO US-ASCII support only, no UTF-8 support // While UTF-8 might work in some cases, we do not guarantee full functionality template <typename StringView> inline auto decompose(const StringView &lhs, const StringView &rhs) { auto const lcs = longest_common_substring(lhs, rhs); // trim spaces, transform to lower const auto trim = [](StringView view) { // we compare suffixes based on this value, it might break UTF chars, but as long as we are // consistent in handling, we do not create bad results std::string str = boost::to_lower_copy(view.to_string()); auto front = str.find_first_not_of(" "); if (front == std::string::npos) return str; auto back = str.find_last_not_of(" "); return str.substr(front, back - front + 1); }; if (lcs.empty()) { return std::make_tuple(trim(lhs), trim(rhs), std::string(), std::string()); } // find the common substring in both auto lhs_pos = lhs.find(lcs); auto rhs_pos = rhs.find(lcs); BOOST_ASSERT(lhs_pos + lcs.size() <= lhs.size()); BOOST_ASSERT(rhs_pos + lcs.size() <= rhs.size()); // prefixes auto lhs_prefix = (lhs_pos > 0) ? lhs.substr(0, lhs_pos) : StringView(); auto rhs_prefix = (rhs_pos > 0) ? rhs.substr(0, rhs_pos) : StringView(); // suffices auto lhs_suffix = lhs.substr(lhs_pos + lcs.size()); auto rhs_suffix = rhs.substr(rhs_pos + lcs.size()); return std::make_tuple(trim(lhs_prefix), trim(lhs_suffix), trim(rhs_prefix), trim(rhs_suffix)); }
inline bool requiresNameAnnounced(const StringView &from_name, const StringView &from_ref, const StringView &from_pronunciation, const StringView &from_exits, const StringView &to_name, const StringView &to_ref, const StringView &to_pronunciation, const StringView &to_exits, const SuffixTable &suffix_table) { // first is empty and the second is not if ((from_name.empty() && from_ref.empty()) && !(to_name.empty() && to_ref.empty())) return true; // FIXME, handle in profile to begin with? // Input for this function should be a struct separating streetname, suffix (e.g. road, // boulevard, North, West ...), and a list of references // check similarity of names const auto names_are_empty = from_name.empty() && to_name.empty(); const auto name_is_contained = boost::starts_with(from_name, to_name) || boost::starts_with(to_name, from_name); const auto checkForPrefixOrSuffixChange = [](const StringView &first, const StringView &second, const SuffixTable &suffix_table) { std::string first_prefix, first_suffix, second_prefix, second_suffix; std::tie(first_prefix, first_suffix, second_prefix, second_suffix) = decompose(first, second); const auto checkTable = [&](const std::string &str) { return str.empty() || suffix_table.isSuffix(str); }; return checkTable(first_prefix) && checkTable(first_suffix) && checkTable(second_prefix) && checkTable(second_suffix); }; const auto is_suffix_change = checkForPrefixOrSuffixChange(from_name, to_name, suffix_table); const auto names_are_equal = from_name == to_name || name_is_contained || is_suffix_change; const auto name_is_removed = !from_name.empty() && to_name.empty(); // references are contained in one another const auto refs_are_empty = from_ref.empty() && to_ref.empty(); const auto ref_is_contained = from_ref.empty() || to_ref.empty() || (from_ref.find(to_ref) != std::string::npos || to_ref.find(from_ref) != std::string::npos); const auto ref_is_removed = !from_ref.empty() && to_ref.empty(); const auto obvious_change = (names_are_empty && refs_are_empty) || (names_are_equal && ref_is_contained) || (names_are_equal && refs_are_empty) || (ref_is_contained && name_is_removed) || (names_are_equal && ref_is_removed) || is_suffix_change; const auto needs_announce = // " (Ref)" -> "Name " and reverse (from_name.empty() && !from_ref.empty() && !to_name.empty() && to_ref.empty()) || (!from_name.empty() && from_ref.empty() && to_name.empty() && !to_ref.empty()); const auto pronunciation_changes = from_pronunciation != to_pronunciation; // when exiting onto ramps, we need to be careful about exit numbers. These can often be only // assigned to the first part of the ramp // // a . . b . c . . d // ` e . . f // // could assign the exit number to `be` when exiting `abcd` instead of the full ramp. // // Issuing a new-name instruction here would result in the turn assuming the short segment to be // irrelevant and remove the exit number in a collapse scenario. We don't want to issue any // instruction from be-ef, since we only loose the exit number. So we want to make sure that we // don't just loose an exit number, when exits change const auto exits_change = from_exits != to_exits; const auto looses_exit = (names_are_equal && !from_exits.empty() && to_exits.empty()); return !obvious_change || needs_announce || pronunciation_changes || (exits_change && !looses_exit); }