From 8a800901b78a29e33bc91b48621cec72964a1f14 Mon Sep 17 00:00:00 2001 From: brettw <brettw@chromium.org> Date: Fri, 10 Jul 2015 11:28:33 -0700 Subject: [PATCH] Replace base::str[n]casecmp with helper functions. Adds CompareCaseInsensitiveASCII and EqualsCaseInsensitiveASCII helper functions and removes base::strcasecmp and base::strncasecmp. This avoids the dangerous locale-sensitive behavior. ClientIsAdvertisingSdchEncoding in sdch_browsertest had the condition inverted, but because it returned true any time the given line wasn't found, the test didn't notice. cups_helper changed most significantly. I redid the loop to use StringPieces which saves a lot of copies. On line 82 cups_helper used to do a prefix match which I'm pretty sure it wanted a regular compare. I changed this. render_text_harfbuzz set "<" operator was also doing a prefix comparison only, when it looks like it really just wanted to compare the strings. file_path passed string pieces into strcasecmp which could then read off the end if they're not null terminated. This patch fixes the bug and calls the native strcasecmp which is probably the best we can do for Posix file names. Removed additional version of the same function in net. Adds a backwards-compat hack for crashpad which improperly uses base from a DEPS-ed in repo. Review URL: https://codereview.chromium.org/1224553010 Cr-Commit-Position: refs/heads/master@{#338324} --- base/files/file_path.cc | 10 ++- base/strings/string_util.cc | 47 +++++++++++++ base/strings/string_util.h | 50 ++++++++++---- base/strings/string_util_posix.h | 8 --- base/strings/string_util_unittest.cc | 20 ++++++ base/strings/string_util_win.h | 8 --- .../fileapi/media_path_filter.cc | 15 ++--- chrome/browser/net/sdch_browsertest.cc | 4 +- .../printing/printing_layout_browsertest.cc | 4 +- .../cloud_print/cloud_print_connector.cc | 2 +- .../cloud_print/cloud_print_proxy_backend.cc | 4 +- .../test/chromedriver/performance_logger.cc | 3 +- components/mime_util/mime_util.cc | 4 +- .../policy/core/common/registry_dict_win.cc | 2 +- .../service_worker/service_worker_types.h | 2 +- content/plugin/webplugin_proxy.cc | 2 +- device/usb/usb_service_impl.cc | 5 +- .../api/web_request/form_data_parser.cc | 8 +-- .../fake_video_capture_device_factory.cc | 2 +- mojo/services/network/http_connection_impl.cc | 9 +-- net/base/mime_sniffer.cc | 35 ++++++---- net/base/mime_util.cc | 12 ++-- net/cookies/cookie_util.cc | 3 +- net/dns/dns_response.cc | 4 +- net/http/http_log_util.cc | 14 ++-- net/http/http_request_headers.cc | 6 +- net/tools/balsa/balsa_headers.h | 2 +- net/tools/balsa/string_piece_utils.h | 23 +------ net/tools/quic/test_tools/http_message.cc | 4 +- .../url_request_http_job_unittest.cc | 2 +- printing/backend/cups_helper.cc | 66 ++++++++++--------- skia/ext/image_operations_bench.cc | 2 +- sql/connection.cc | 3 +- tools/gn/filesystem_utils.cc | 2 +- ui/base/l10n/l10n_util.cc | 2 +- ui/gfx/render_text_harfbuzz.cc | 2 +- ui/gfx/test/fontconfig_util_linux.cc | 3 +- 37 files changed, 227 insertions(+), 167 deletions(-) diff --git a/base/files/file_path.cc b/base/files/file_path.cc index 92123533aaa55..51656d26d3af5 100644 --- a/base/files/file_path.cc +++ b/base/files/file_path.cc @@ -10,9 +10,6 @@ #include "base/basictypes.h" #include "base/logging.h" #include "base/pickle.h" - -// These includes are just for the *Hack functions, and should be removed -// when those functions are removed. #include "base/strings/string_piece.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" @@ -1259,11 +1256,12 @@ int FilePath::CompareIgnoreCase(StringPieceType string1, #else // << WIN. MACOSX | other (POSIX) >> -// Generic (POSIX) implementation of file string comparison. -// TODO(rolandsteiner) check if this is sufficient/correct. +// Generic Posix system comparisons. int FilePath::CompareIgnoreCase(StringPieceType string1, StringPieceType string2) { - int comparison = strcasecmp(string1.data(), string2.data()); + // Specifically need null termianted strings for this API call. + int comparison = strcasecmp(string1.as_string().c_str(), + string2.as_string().c_str()); if (comparison < 0) return -1; if (comparison > 0) diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc index 5b727ce0b4e2a..fcd8ddf12e4ed 100644 --- a/base/strings/string_util.cc +++ b/base/strings/string_util.cc @@ -140,6 +140,53 @@ bool IsWprintfFormatPortable(const wchar_t* format) { return true; } +template<class StringType> +int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a, + BasicStringPiece<StringType> b) { + // Find the first characters that aren't equal and compare them. If the end + // of one of the strings is found before a nonequal character, the lengths + // of the strings are compared. + size_t i = 0; + while (i < a.length() && i < b.length()) { + typename StringType::value_type lower_a = ToLowerASCII(a[i]); + typename StringType::value_type lower_b = ToLowerASCII(b[i]); + if (lower_a < lower_b) + return -1; + if (lower_a > lower_b) + return 1; + i++; + } + + // End of one string hit before finding a different character. Expect the + // common case to be "strings equal" at this point so check that first. + if (a.length() == b.length()) + return 0; + + if (a.length() < b.length()) + return -1; + return 1; +} + +int CompareCaseInsensitiveASCII(base::StringPiece a, base::StringPiece b) { + return CompareCaseInsensitiveASCIIT<std::string>(a, b); +} + +int CompareCaseInsensitiveASCII(base::StringPiece16 a, base::StringPiece16 b) { + return CompareCaseInsensitiveASCIIT<base::string16>(a, b); +} + +bool EqualsCaseInsensitiveASCII(base::StringPiece a, base::StringPiece b) { + if (a.length() != b.length()) + return false; + return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0; +} + +bool EqualsCaseInsensitiveASCII(base::StringPiece16 a, base::StringPiece16 b) { + if (a.length() != b.length()) + return false; + return CompareCaseInsensitiveASCIIT<base::string16>(a, b) == 0; +} + const std::string& EmptyString() { return EmptyStrings::GetInstance()->s; } diff --git a/base/strings/string_util.h b/base/strings/string_util.h index 62b3605a8933b..5d26f1c54142f 100644 --- a/base/strings/string_util.h +++ b/base/strings/string_util.h @@ -21,20 +21,10 @@ namespace base { -// C standard-library functions like "strncasecmp" and "snprintf" that aren't -// cross-platform are provided as "base::strncasecmp", and their prototypes -// are listed below. These functions are then implemented as inline calls -// to the platform-specific equivalents in the platform-specific headers. - -// Compares the two strings s1 and s2 without regard to case using -// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if -// s2 > s1 according to a lexicographic comparison. -int strcasecmp(const char* s1, const char* s2); - -// Compares up to count characters of s1 and s2 without regard to case using -// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if -// s2 > s1 according to a lexicographic comparison. -int strncasecmp(const char* s1, const char* s2, size_t count); +// C standard-library functions that aren't cross-platform are provided as +// "base::...", and their prototypes are listed below. These functions are +// then implemented as inline calls to the platform-specific equivalents in the +// platform-specific headers. // Wrapper for vsnprintf that always null-terminates and always returns the // number of characters that would be in an untruncated formatted @@ -56,6 +46,19 @@ inline int snprintf(char* buffer, size_t size, const char* format, ...) { return result; } +// TODO(mark) http://crbug.com/472900 crashpad shouldn't use base while +// being DEPSed in. This backwards-compat hack is provided until crashpad is +// updated. +#if defined(OS_WIN) +inline int strcasecmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +#else // Posix +inline int strcasecmp(const char* string1, const char* string2) { + return ::strcasecmp(string1, string2); +} +#endif + // BSD-style safe and consistent string copy functions. // Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|. // Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as @@ -102,10 +105,13 @@ template <class Char> inline Char ToUpperASCII(Char c) { // Function objects to aid in comparing/searching strings. +// DO NOT USE. tolower() will given incorrect results for non-ASCII characters. +// Use the ASCII version, base::i18n::ToLower, or base::i18n::FoldCase. template<typename Char> struct CaseInsensitiveCompare { public: bool operator()(Char x, Char y) const { // TODO(darin): Do we really want to do locale sensitive comparisons here? + // ANSWER(brettw): No. // See http://crbug.com/24917 return tolower(x) == tolower(y); } @@ -118,6 +124,22 @@ template<typename Char> struct CaseInsensitiveCompareASCII { } }; +// Like strcasecmp for case-insensitive ASCII characters only. Returns: +// -1 (a < b) +// 0 (a == b) +// 1 (a > b) +// (unlike strcasecmp which can return values greater or less than 1/-1). For +// full Unicode support, use base::i18n::ToLower or base::i18h::FoldCase +// and then just call the normal string operators on the result. +BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b); +BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b); + +// Equality for ASCII case-insensitive comparisons. For full Unicode support, +// use base::i18n::ToLower or base::i18h::FoldCase and then compare with either +// == or !=. +BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b); +BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b); + // These threadsafe functions return references to globally unique empty // strings. // diff --git a/base/strings/string_util_posix.h b/base/strings/string_util_posix.h index d31a9fcbefd28..9e96697ff5625 100644 --- a/base/strings/string_util_posix.h +++ b/base/strings/string_util_posix.h @@ -20,14 +20,6 @@ inline char* strdup(const char* str) { return ::strdup(str); } -inline int strcasecmp(const char* string1, const char* string2) { - return ::strcasecmp(string1, string2); -} - -inline int strncasecmp(const char* string1, const char* string2, size_t count) { - return ::strncasecmp(string1, string2, count); -} - inline int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments) { return ::vsnprintf(buffer, size, format, arguments); diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc index 02b184cc62023..1593f8189679a 100644 --- a/base/strings/string_util_unittest.cc +++ b/base/strings/string_util_unittest.cc @@ -1056,6 +1056,26 @@ TEST(StringUtilTest, ContainsOnlyChars) { kWhitespaceUTF16)); } +TEST(StringUtilTest, CompareCaseInsensitiveASCII) { + EXPECT_EQ(0, CompareCaseInsensitiveASCII("", "")); + EXPECT_EQ(0, CompareCaseInsensitiveASCII("Asdf", "aSDf")); + + // Differing lengths. + EXPECT_EQ(-1, CompareCaseInsensitiveASCII("Asdf", "aSDfA")); + EXPECT_EQ(1, CompareCaseInsensitiveASCII("AsdfA", "aSDf")); + + // Differing values. + EXPECT_EQ(-1, CompareCaseInsensitiveASCII("AsdfA", "aSDfb")); + EXPECT_EQ(1, CompareCaseInsensitiveASCII("Asdfb", "aSDfA")); +} + +TEST(StringUtilTest, EqualsCaseInsensitiveASCII) { + EXPECT_TRUE(EqualsCaseInsensitiveASCII("", "")); + EXPECT_TRUE(EqualsCaseInsensitiveASCII("Asdf", "aSDF")); + EXPECT_FALSE(EqualsCaseInsensitiveASCII("bsdf", "aSDF")); + EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", "aSDFz")); +} + class WriteIntoTest : public testing::Test { protected: static void WritesCorrectly(size_t num_chars) { diff --git a/base/strings/string_util_win.h b/base/strings/string_util_win.h index 7c1e34cf8fcff..839a799a157f0 100644 --- a/base/strings/string_util_win.h +++ b/base/strings/string_util_win.h @@ -20,14 +20,6 @@ inline char* strdup(const char* str) { return _strdup(str); } -inline int strcasecmp(const char* s1, const char* s2) { - return _stricmp(s1, s2); -} - -inline int strncasecmp(const char* s1, const char* s2, size_t count) { - return _strnicmp(s1, s2, count); -} - inline int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments) { int length = vsnprintf_s(buffer, size, size - 1, format, arguments); diff --git a/chrome/browser/media_galleries/fileapi/media_path_filter.cc b/chrome/browser/media_galleries/fileapi/media_path_filter.cc index 0212e11136035..5b27f1019ab28 100644 --- a/chrome/browser/media_galleries/fileapi/media_path_filter.cc +++ b/chrome/browser/media_galleries/fileapi/media_path_filter.cc @@ -126,15 +126,12 @@ bool MediaPathFilter::ShouldSkip(const base::FilePath& path) { const char win_98_recycle_bin_name[] = "RECYCLED"; const char win_xp_recycle_bin_name[] = "RECYCLER"; const char win_vista_recycle_bin_name[] = "$Recycle.bin"; - if ((base::strncasecmp(base_name.c_str(), - win_98_recycle_bin_name, - strlen(win_98_recycle_bin_name)) == 0) || - (base::strncasecmp(base_name.c_str(), - win_xp_recycle_bin_name, - strlen(win_xp_recycle_bin_name)) == 0) || - (base::strncasecmp(base_name.c_str(), - win_vista_recycle_bin_name, - strlen(win_vista_recycle_bin_name)) == 0)) + if (base::StartsWith(base_name, win_98_recycle_bin_name, + base::CompareCase::INSENSITIVE_ASCII) || + base::StartsWith(base_name, win_xp_recycle_bin_name, + base::CompareCase::INSENSITIVE_ASCII) || + base::StartsWith(base_name, win_vista_recycle_bin_name, + base::CompareCase::INSENSITIVE_ASCII)) return true; #endif // defined(OS_WIN) return false; diff --git a/chrome/browser/net/sdch_browsertest.cc b/chrome/browser/net/sdch_browsertest.cc index 7a1cb7b69211d..9c93d6b841dda 100644 --- a/chrome/browser/net/sdch_browsertest.cc +++ b/chrome/browser/net/sdch_browsertest.cc @@ -108,7 +108,7 @@ bool GetRequestHeader(const HttpRequestHeaderMap& map, std::string* value) { for (HttpRequestHeaderMap::const_iterator it = map.begin(); it != map.end(); ++it) { - if (!base::strcasecmp(it->first.c_str(), header)) { + if (base::EqualsCaseInsensitiveASCII(it->first, header)) { *value = it->second; return true; } @@ -170,7 +170,7 @@ class SdchResponseHandler { return false; base::StringTokenizer tokenizer(value, " ,"); while (tokenizer.GetNext()) { - if (base::strcasecmp(tokenizer.token().c_str(), "sdch")) + if (base::EqualsCaseInsensitiveASCII(tokenizer.token(), "sdch")) return true; } return false; diff --git a/chrome/browser/printing/printing_layout_browsertest.cc b/chrome/browser/printing/printing_layout_browsertest.cc index 4e1d2b731d83b..4755a18a00755 100644 --- a/chrome/browser/printing/printing_layout_browsertest.cc +++ b/chrome/browser/printing/printing_layout_browsertest.cc @@ -207,7 +207,7 @@ class PrintingLayoutTest : public PrintingTest<InProcessBrowserTest>, base::FilePath file; while (!(file = enumerator.Next()).empty()) { std::wstring ext = file.Extension(); - if (base::strcasecmp(base::WideToUTF8(ext).c_str(), ".emf") == 0) { + if (base::EqualsCaseInsensitiveASCII(base::WideToUTF8(ext), ".emf")) { EXPECT_FALSE(found_emf) << "Found a leftover .EMF file: \"" << emf_file << "\" and \"" << file.value() << "\" when looking for \"" << verification_name << "\""; @@ -215,7 +215,7 @@ class PrintingLayoutTest : public PrintingTest<InProcessBrowserTest>, emf_file = file.value(); continue; } - if (base::strcasecmp(base::WideToUTF8(ext).c_str(), ".prn") == 0) { + if (base::EqualsCaseInsensitiveASCII(base::WideToUTF8(ext), ".prn")) { EXPECT_FALSE(found_prn) << "Found a leftover .PRN file: \"" << prn_file << "\" and \"" << file.value() << "\" when looking for \"" << verification_name << "\""; diff --git a/chrome/service/cloud_print/cloud_print_connector.cc b/chrome/service/cloud_print/cloud_print_connector.cc index a1f6be7f667ae..f53c865e6abe7 100644 --- a/chrome/service/cloud_print/cloud_print_connector.cc +++ b/chrome/service/cloud_print/cloud_print_connector.cc @@ -653,7 +653,7 @@ void CloudPrintConnector::OnReceivePrinterCaps( bool CloudPrintConnector::IsSamePrinter(const std::string& name1, const std::string& name2) const { - return (0 == base::strcasecmp(name1.c_str(), name2.c_str())); + return base::EqualsCaseInsensitiveASCII(name1, name2); } } // namespace cloud_print diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc index f93215dbd66fb..53485ccdf1618 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc @@ -550,8 +550,8 @@ void CloudPrintProxyBackend::Core::OnIncomingNotification( DCHECK(base::MessageLoop::current() == backend_->core_thread_.message_loop()); VLOG(1) << "CP_CONNECTOR: Incoming notification."; - if (0 == base::strcasecmp(kCloudPrintPushNotificationsSource, - notification.channel.c_str())) + if (base::EqualsCaseInsensitiveASCII(kCloudPrintPushNotificationsSource, + notification.channel)) HandlePrinterNotification(notification.data); } diff --git a/chrome/test/chromedriver/performance_logger.cc b/chrome/test/chromedriver/performance_logger.cc index 37e66f40f2803..f97385b6d9143 100644 --- a/chrome/test/chromedriver/performance_logger.cc +++ b/chrome/test/chromedriver/performance_logger.cc @@ -43,7 +43,8 @@ bool IsEnabled(const PerfLoggingPrefs::InspectorDomainStatus& domain_status) { bool ShouldRequestTraceEvents(const std::string& command) { for (size_t i_domain = 0; i_domain < arraysize(kRequestTraceCommands); ++i_domain) { - if (base::strcasecmp(command.c_str(), kRequestTraceCommands[i_domain]) == 0) + if (base::EqualsCaseInsensitiveASCII(command, + kRequestTraceCommands[i_domain])) return true; } return false; diff --git a/components/mime_util/mime_util.cc b/components/mime_util/mime_util.cc index 3841fbbb69074..ef5e0daaefdda 100644 --- a/components/mime_util/mime_util.cc +++ b/components/mime_util/mime_util.cc @@ -221,8 +221,8 @@ net::CertificateMimeType GetCertificateMimeTypeForMimeType( // Don't create a map, there is only one entry in the table, // except on Android. for (size_t i = 0; i < arraysize(kSupportedCertificateTypes); ++i) { - if (base::strcasecmp(mime_type.c_str(), - kSupportedCertificateTypes[i].mime_type) == 0) { + if (base::EqualsCaseInsensitiveASCII( + mime_type, kSupportedCertificateTypes[i].mime_type)) { return kSupportedCertificateTypes[i].cert_type; } } diff --git a/components/policy/core/common/registry_dict_win.cc b/components/policy/core/common/registry_dict_win.cc index 132adcaddea05..dd04beec1ab68 100644 --- a/components/policy/core/common/registry_dict_win.cc +++ b/components/policy/core/common/registry_dict_win.cc @@ -136,7 +136,7 @@ scoped_ptr<base::Value> ConvertValue(const base::Value& value, bool CaseInsensitiveStringCompare::operator()(const std::string& a, const std::string& b) const { - return base::strcasecmp(a.c_str(), b.c_str()) < 0; + return base::CompareCaseInsensitiveASCII(a, b) < 0; } RegistryDict::RegistryDict() {} diff --git a/content/common/service_worker/service_worker_types.h b/content/common/service_worker/service_worker_types.h index 917c9ed9ff405..631c56320deb2 100644 --- a/content/common/service_worker/service_worker_types.h +++ b/content/common/service_worker/service_worker_types.h @@ -102,7 +102,7 @@ enum ServiceWorkerFetchEventResult { struct ServiceWorkerCaseInsensitiveCompare { bool operator()(const std::string& lhs, const std::string& rhs) const { - return base::strcasecmp(lhs.c_str(), rhs.c_str()) < 0; + return base::CompareCaseInsensitiveASCII(lhs, rhs) < 0; } }; diff --git a/content/plugin/webplugin_proxy.cc b/content/plugin/webplugin_proxy.cc index 3c607143ee892..6b6d696ca5da8 100644 --- a/content/plugin/webplugin_proxy.cc +++ b/content/plugin/webplugin_proxy.cc @@ -280,7 +280,7 @@ void WebPluginProxy::HandleURLRequest(const char* url, int notify_id, bool popups_allowed, bool notify_redirects) { - if (!target && (0 == base::strcasecmp(method, "GET"))) { + if (!target && base::EqualsCaseInsensitiveASCII(method, "GET")) { // Please refer to https://bugzilla.mozilla.org/show_bug.cgi?id=366082 // for more details on this. if (delegate_->GetQuirks() & diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc index ea7ad7f498108..2261ad6930bdd 100644 --- a/device/usb/usb_service_impl.cc +++ b/device/usb/usb_service_impl.cc @@ -127,10 +127,9 @@ bool IsWinUsbInterface(const std::string& device_path) { } USB_LOG(DEBUG) << "Driver for " << device_path << " is " << buffer << "."; - if (base::strncasecmp("WinUSB", (const char*)&buffer[0], sizeof "WinUSB") == - 0) { + if (base::StartsWith(reinterpret_cast<const char*>(buffer), "WinUSB", + base::CompareCase::INSENSITIVE_ASCII)) return true; - } return false; } diff --git a/extensions/browser/api/web_request/form_data_parser.cc b/extensions/browser/api/web_request/form_data_parser.cc index 31b6fe8aadfa1..f12c34face959 100644 --- a/extensions/browser/api/web_request/form_data_parser.cc +++ b/extensions/browser/api/web_request/form_data_parser.cc @@ -315,11 +315,11 @@ scoped_ptr<FormDataParser> FormDataParser::CreateFromContentTypeHeader( const std::string content_type( content_type_header->substr(0, content_type_header->find(';'))); - if (base::strcasecmp( - content_type.c_str(), "application/x-www-form-urlencoded") == 0) { + if (base::EqualsCaseInsensitiveASCII(content_type, + "application/x-www-form-urlencoded")) { choice = URL_ENCODED; - } else if (base::strcasecmp( - content_type.c_str(), "multipart/form-data") == 0) { + } else if (base::EqualsCaseInsensitiveASCII(content_type, + "multipart/form-data")) { static const char kBoundaryString[] = "boundary="; size_t offset = content_type_header->find(kBoundaryString); if (offset == std::string::npos) { diff --git a/media/video/capture/fake_video_capture_device_factory.cc b/media/video/capture/fake_video_capture_device_factory.cc index a9d32dee2eda1..302223fd7ed43 100644 --- a/media/video/capture/fake_video_capture_device_factory.cc +++ b/media/video/capture/fake_video_capture_device_factory.cc @@ -26,7 +26,7 @@ scoped_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::Create( FakeVideoCaptureDevice::FakeVideoCaptureDeviceType fake_vcd_type; if (option.empty()) fake_vcd_type = FakeVideoCaptureDevice::USING_OWN_BUFFERS; - else if (base:: strcasecmp(option.c_str(), "triplanar") == 0) + else if (base::EqualsCaseInsensitiveASCII(option, "triplanar")) fake_vcd_type = FakeVideoCaptureDevice::USING_OWN_BUFFERS_TRIPLANAR; else fake_vcd_type = FakeVideoCaptureDevice::USING_CLIENT_BUFFERS; diff --git a/mojo/services/network/http_connection_impl.cc b/mojo/services/network/http_connection_impl.cc index 2df12aa7b50d7..ad3347d9d43ca 100644 --- a/mojo/services/network/http_connection_impl.cc +++ b/mojo/services/network/http_connection_impl.cc @@ -375,11 +375,12 @@ void HttpConnectionImpl::OnFinishedReadingResponseBody( // // TODO(yzshen): Consider adding to net::HttpServerResponseInfo a simple // setter for body which doesn't fiddle with headers. - if (base::strcasecmp(header.name.data(), - net::HttpRequestHeaders::kContentLength) == 0) { + base::StringPiece name_piece(header.name.data(), header.name.size()); + if (base::EqualsCaseInsensitiveASCII( + name_piece, net::HttpRequestHeaders::kContentLength)) { continue; - } else if (base::strcasecmp(header.name.data(), - net::HttpRequestHeaders::kContentType) == 0) { + } else if (base::EqualsCaseInsensitiveASCII( + name_piece, net::HttpRequestHeaders::kContentType)) { content_type = header.value; continue; } diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc index 907c7c4f09989..668e89831f808 100644 --- a/net/base/mime_sniffer.cc +++ b/net/base/mime_sniffer.cc @@ -344,8 +344,10 @@ static bool MatchMagicNumber(const char* content, bool match = false; if (magic_entry.is_string) { if (content_strlen >= len) { - // String comparisons are case-insensitive - match = (base::strncasecmp(magic_entry.magic, content, len) == 0); + // Do a case-insensitive prefix comparison. + DCHECK_EQ(strlen(magic_entry.magic), len); + match = base::EqualsCaseInsensitiveASCII(magic_entry.magic, + base::StringPiece(content, len)); } } else { if (size >= len) { @@ -462,11 +464,12 @@ static bool SniffForOfficeDocs(const char* content, if (url_path.length() < kOfficeExtensionTypes[i].extension_len) continue; - const char* extension = - &url_path[url_path.length() - kOfficeExtensionTypes[i].extension_len]; - - if (0 == base::strncasecmp(extension, kOfficeExtensionTypes[i].extension, - kOfficeExtensionTypes[i].extension_len)) { + base::StringPiece extension = base::StringPiece(url_path).substr( + url_path.length() - kOfficeExtensionTypes[i].extension_len); + if (base::EqualsCaseInsensitiveASCII( + extension, + base::StringPiece(kOfficeExtensionTypes[i].extension, + kOfficeExtensionTypes[i].extension_len))) { type = kOfficeExtensionTypes[i].doc_type; break; } @@ -608,14 +611,22 @@ static bool SniffXML(const char* content, if (!pos) return false; - if ((pos + sizeof("<?xml") - 1 <= end) && - (base::strncasecmp(pos, "<?xml", sizeof("<?xml") - 1) == 0)) { + static const char kXmlPrefix[] = "<?xml"; + static const size_t kXmlPrefixLength = arraysize(kXmlPrefix) - 1; + static const char kDocTypePrefix[] = "<!DOCTYPE"; + static const size_t kDocTypePrefixLength = arraysize(kDocTypePrefix) - 1; + + if ((pos + kXmlPrefixLength <= end) && + base::EqualsCaseInsensitiveASCII( + base::StringPiece(pos, kXmlPrefixLength), + base::StringPiece(kXmlPrefix, kXmlPrefixLength))) { // Skip XML declarations. ++pos; continue; - } else if ((pos + sizeof("<!DOCTYPE") - 1 <= end) && - (base::strncasecmp(pos, "<!DOCTYPE", sizeof("<!DOCTYPE") - 1) == - 0)) { + } else if ((pos + kDocTypePrefixLength <= end) && + base::EqualsCaseInsensitiveASCII( + base::StringPiece(pos, kDocTypePrefixLength), + base::StringPiece(kDocTypePrefix, kDocTypePrefixLength))) { // Skip DOCTYPE declarations. ++pos; continue; diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc index ae4781a68ae82..27c547b6e0b37 100644 --- a/net/base/mime_util.cc +++ b/net/base/mime_util.cc @@ -116,8 +116,11 @@ const char* FindMimeType(const MimeInfo* mappings, const char* extensions = mappings[i].extensions; for (;;) { size_t end_pos = strcspn(extensions, ","); + // The length check is required to prevent the StringPiece below from + // including uninitialized memory if ext is longer than extensions. if (end_pos == ext.size() && - base::strncasecmp(extensions, ext.data(), ext.size()) == 0) + base::EqualsCaseInsensitiveASCII( + base::StringPiece(extensions, ext.size()), ext)) return mappings[i].mime_type; extensions += end_pos; if (!*extensions) @@ -268,13 +271,10 @@ bool MimeUtil::MatchesMimeType(const std::string& mime_type_pattern, const std::string::size_type star = base_pattern.find('*'); if (star == std::string::npos) { - if (base_pattern.size() == base_type.size() && - base::strncasecmp(base_pattern.data(), base_type.data(), - base_pattern.size()) == 0) { + if (base::EqualsCaseInsensitiveASCII(base_pattern, base_type)) return MatchesMimeTypeParameters(mime_type_pattern, mime_type); - } else { + else return false; - } } // Test length to prevent overlap between |left| and |right|. diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc index 2723363e2fb4e..b9c7e8d601f8e 100644 --- a/net/cookies/cookie_util.cc +++ b/net/cookies/cookie_util.cc @@ -125,7 +125,8 @@ base::Time ParseCookieTime(const std::string& time_string) { if (!found_month) { for (int i = 0; i < kMonthsLen; ++i) { // Match prefix, so we could match January, etc - if (base::strncasecmp(token.c_str(), kMonths[i], 3) == 0) { + if (base::StartsWith(token, base::StringPiece(kMonths[i], 3), + base::CompareCase::INSENSITIVE_ASCII)) { exploded.month = i + 1; found_month = true; break; diff --git a/net/dns/dns_response.cc b/net/dns/dns_response.cc index 64db818b2b942..730206ca60801 100644 --- a/net/dns/dns_response.cc +++ b/net/dns/dns_response.cc @@ -303,7 +303,7 @@ DnsResponse::Result DnsResponse::ParseToAddressList( if (!ip_addresses.empty()) return DNS_CNAME_AFTER_ADDRESS; - if (base::strcasecmp(record.name.c_str(), expected_name.c_str()) != 0) + if (!base::EqualsCaseInsensitiveASCII(record.name, expected_name)) return DNS_NAME_MISMATCH; if (record.rdata.size() != @@ -315,7 +315,7 @@ DnsResponse::Result DnsResponse::ParseToAddressList( if (record.rdata.size() != expected_size) return DNS_SIZE_MISMATCH; - if (base::strcasecmp(record.name.c_str(), expected_name.c_str()) != 0) + if (!base::EqualsCaseInsensitiveASCII(record.name, expected_name)) return DNS_NAME_MISMATCH; ttl_sec = std::min(ttl_sec, record.ttl); diff --git a/net/http/http_log_util.cc b/net/http/http_log_util.cc index 0467fb605ab40..8e071e34109a7 100644 --- a/net/http/http_log_util.cc +++ b/net/http/http_log_util.cc @@ -45,15 +45,15 @@ std::string ElideHeaderValueForNetLog(NetLogCaptureMode capture_mode, // Note: this logic should be kept in sync with stripCookiesAndLoginInfo in // chrome/browser/resources/net_internals/log_view_painter.js. - if (!base::strcasecmp(header.c_str(), "set-cookie") || - !base::strcasecmp(header.c_str(), "set-cookie2") || - !base::strcasecmp(header.c_str(), "cookie") || - !base::strcasecmp(header.c_str(), "authorization") || - !base::strcasecmp(header.c_str(), "proxy-authorization")) { + if (base::EqualsCaseInsensitiveASCII(header, "set-cookie") || + base::EqualsCaseInsensitiveASCII(header, "set-cookie2") || + base::EqualsCaseInsensitiveASCII(header, "cookie") || + base::EqualsCaseInsensitiveASCII(header, "authorization") || + base::EqualsCaseInsensitiveASCII(header, "proxy-authorization")) { redact_begin = value.begin(); redact_end = value.end(); - } else if (!base::strcasecmp(header.c_str(), "www-authenticate") || - !base::strcasecmp(header.c_str(), "proxy-authenticate")) { + } else if (base::EqualsCaseInsensitiveASCII(header, "www-authenticate") || + base::EqualsCaseInsensitiveASCII(header, "proxy-authenticate")) { // Look for authentication information from data received from the server // in multi-round Negotiate authentication. HttpAuthChallengeTokenizer challenge(value.begin(), value.end()); diff --git a/net/http/http_request_headers.cc b/net/http/http_request_headers.cc index 004d0659512c6..c2eee59af95f8 100644 --- a/net/http/http_request_headers.cc +++ b/net/http/http_request_headers.cc @@ -241,8 +241,7 @@ HttpRequestHeaders::HeaderVector::iterator HttpRequestHeaders::FindHeader(const base::StringPiece& key) { for (HeaderVector::iterator it = headers_.begin(); it != headers_.end(); ++it) { - if (key.length() == it->key.length() && - !base::strncasecmp(key.data(), it->key.data(), key.length())) + if (base::EqualsCaseInsensitiveASCII(key, it->key)) return it; } @@ -253,8 +252,7 @@ HttpRequestHeaders::HeaderVector::const_iterator HttpRequestHeaders::FindHeader(const base::StringPiece& key) const { for (HeaderVector::const_iterator it = headers_.begin(); it != headers_.end(); ++it) { - if (key.length() == it->key.length() && - !base::strncasecmp(key.data(), it->key.data(), key.length())) + if (base::EqualsCaseInsensitiveASCII(key, it->key)) return it; } diff --git a/net/tools/balsa/balsa_headers.h b/net/tools/balsa/balsa_headers.h index 3edcf677703b7..3fc01c4c157a0 100644 --- a/net/tools/balsa/balsa_headers.h +++ b/net/tools/balsa/balsa_headers.h @@ -538,7 +538,7 @@ class BalsaHeaders { do { iterator_base::increment(); } while (!AtEnd() && - !StringPieceUtils::EqualIgnoreCase(key_, (**this).first)); + !base::EqualsCaseInsensitiveASCII(key_, (**this).first)); return *this; } diff --git a/net/tools/balsa/string_piece_utils.h b/net/tools/balsa/string_piece_utils.h index 7d8a1aaaee287..6d8967a014219 100644 --- a/net/tools/balsa/string_piece_utils.h +++ b/net/tools/balsa/string_piece_utils.h @@ -65,31 +65,10 @@ struct StringPieceCaseHash { }; #endif // COMPILER_MSVC -struct StringPieceUtils { - // ASCII case-insensitive equality. - static bool EqualIgnoreCase(const base::StringPiece& piece1, - const base::StringPiece& piece2) { - base::StringPiece::const_iterator p1i = piece1.begin(); - base::StringPiece::const_iterator p2i = piece2.begin(); - if (piece1.empty() && piece2.empty()) { - return true; - } else if (piece1.size() != piece2.size()) { - return false; - } - while (p1i != piece1.end() && p2i != piece2.end()) { - if (base::ToLowerASCII(*p1i) != base::ToLowerASCII(*p2i)) - return false; - ++p1i; - ++p2i; - } - return true; - } -}; - struct StringPieceCaseEqual { bool operator()(const base::StringPiece& piece1, const base::StringPiece& piece2) const { - return StringPieceUtils::EqualIgnoreCase(piece1, piece2); + return base::EqualsCaseInsensitiveASCII(piece1, piece2); } }; diff --git a/net/tools/quic/test_tools/http_message.cc b/net/tools/quic/test_tools/http_message.cc index ad13f5c2f45d3..b1520917b43cb 100644 --- a/net/tools/quic/test_tools/http_message.cc +++ b/net/tools/quic/test_tools/http_message.cc @@ -158,8 +158,8 @@ void HTTPMessage::ValidateMessage() const { for (vector<StringPiece>::iterator it = transfer_encodings.begin(); it != transfer_encodings.end(); ++it) { - CHECK(StringPieceUtils::EqualIgnoreCase("identity", *it) || - StringPieceUtils::EqualIgnoreCase("chunked", *it)) << *it; + CHECK(base::EqualsCaseInsensitiveASCII("identity", *it) || + base::EqualsCaseInsensitiveASCII("chunked", *it)) << *it; } vector<StringPiece> content_lengths; diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc index fde6568d73916..80e421628a48d 100644 --- a/net/url_request/url_request_http_job_unittest.cc +++ b/net/url_request/url_request_http_job_unittest.cc @@ -77,7 +77,7 @@ class URLRequestHttpJobTest : public ::testing::Test { for (const std::string& token : base::SplitString(encoding_headers, ", ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) { - if (!base::strncasecmp(token.data(), "sdch", token.length())) + if (base::EqualsCaseInsensitiveASCII(token, "sdch")) return true; } return false; diff --git a/printing/backend/cups_helper.cc b/printing/backend/cups_helper.cc index c0271b2a2872f..79e33fcf705b8 100644 --- a/printing/backend/cups_helper.cc +++ b/printing/backend/cups_helper.cc @@ -49,48 +49,45 @@ void ParseLpOptions(const base::FilePath& filepath, const char kDefault[] = "default"; const size_t kDestLen = sizeof(kDest) - 1; const size_t kDefaultLen = sizeof(kDefault) - 1; - std::vector<std::string> lines; - base::SplitString(content, '\n', &lines); - for (size_t i = 0; i < lines.size(); ++i) { - std::string line = lines[i]; - if (line.empty()) - continue; - - if (base::strncasecmp (line.c_str(), kDefault, kDefaultLen) == 0 && + for (base::StringPiece line : + base::SplitStringPiece(content, "\n", base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY)) { + if (base::StartsWith(line, base::StringPiece(kDefault, kDefaultLen), + base::CompareCase::INSENSITIVE_ASCII) && isspace(line[kDefaultLen])) { line = line.substr(kDefaultLen); - } else if (base::strncasecmp (line.c_str(), kDest, kDestLen) == 0 && + } else if (base::StartsWith(line, base::StringPiece(kDest, kDestLen), + base::CompareCase::INSENSITIVE_ASCII) && isspace(line[kDestLen])) { line = line.substr(kDestLen); } else { continue; } - base::TrimWhitespaceASCII(line, base::TRIM_ALL, &line); + line = base::TrimWhitespaceASCII(line, base::TRIM_ALL); if (line.empty()) continue; size_t space_found = line.find(' '); - if (space_found == std::string::npos) + if (space_found == base::StringPiece::npos) continue; - std::string name = line.substr(0, space_found); + base::StringPiece name = line.substr(0, space_found); if (name.empty()) continue; - if (base::strncasecmp(printer_name.c_str(), name.c_str(), - name.length()) != 0) { + if (!base::EqualsCaseInsensitiveASCII(printer_name, name)) continue; // This is not the required printer. - } line = line.substr(space_found + 1); // Remove extra spaces. - base::TrimWhitespaceASCII(line, base::TRIM_ALL, &line); + line = base::TrimWhitespaceASCII(line, base::TRIM_ALL); if (line.empty()) continue; - // Parse the selected printer custom options. - *num_options = cupsParseOptions(line.c_str(), 0, options); + // Parse the selected printer custom options. Need to pass a + // null-terminated string. + *num_options = cupsParseOptions(line.as_string().c_str(), 0, options); } } @@ -157,9 +154,12 @@ bool GetBasicColorModelSettings(ppd_file_t* ppd, if (marked_choice) { *color_is_default = - (base::strcasecmp(marked_choice->choice, printing::kBlack) != 0) && - (base::strcasecmp(marked_choice->choice, printing::kGray) != 0) && - (base::strcasecmp(marked_choice->choice, printing::kGrayscale) != 0); + !base::EqualsCaseInsensitiveASCII(marked_choice->choice, + printing::kBlack) && + !base::EqualsCaseInsensitiveASCII(marked_choice->choice, + printing::kGray) && + !base::EqualsCaseInsensitiveASCII(marked_choice->choice, + printing::kGrayscale); } return true; } @@ -190,10 +190,12 @@ bool GetPrintOutModeColorSettings(ppd_file_t* ppd, printout_mode->defchoice); } if (printout_mode_choice) { - if ((base::strcasecmp(printout_mode_choice->choice, - printing::kNormalGray) == 0) || - (base::strcasecmp(printout_mode_choice->choice, kHighGray) == 0) || - (base::strcasecmp(printout_mode_choice->choice, kDraftGray) == 0)) { + if (base::EqualsCaseInsensitiveASCII(printout_mode_choice->choice, + printing::kNormalGray) || + base::EqualsCaseInsensitiveASCII(printout_mode_choice->choice, + kHighGray) || + base::EqualsCaseInsensitiveASCII(printout_mode_choice->choice, + kDraftGray)) { *color_model_for_black = printing::PRINTOUTMODE_NORMAL_GRAY; *color_is_default = false; } @@ -223,8 +225,8 @@ bool GetColorModeSettings(ppd_file_t* ppd, } if (mode_choice) { - *color_is_default = - (base::strcasecmp(mode_choice->choice, printing::kColor) == 0); + *color_is_default = base::EqualsCaseInsensitiveASCII( + mode_choice->choice, printing::kColor); } return true; } @@ -249,8 +251,8 @@ bool GetHPColorSettings(ppd_file_t* ppd, color_mode_option->defchoice); } if (mode_choice) { - *color_is_default = - (base::strcasecmp(mode_choice->choice, printing::kColor) == 0); + *color_is_default = base::EqualsCaseInsensitiveASCII( + mode_choice->choice, printing::kColor); } return true; } @@ -279,8 +281,8 @@ bool GetProcessColorModelSettings(ppd_file_t* ppd, } if (mode_choice) { - *color_is_default = - (base::strcasecmp(mode_choice->choice, printing::kGreyscale) != 0); + *color_is_default = !base::EqualsCaseInsensitiveASCII( + mode_choice->choice, printing::kGreyscale); } return true; } @@ -383,7 +385,7 @@ bool ParsePpdCapabilities( if (duplex_choice) { caps.duplex_capable = true; - if (base::strcasecmp(duplex_choice->choice, kDuplexNone) != 0) + if (!base::EqualsCaseInsensitiveASCII(duplex_choice->choice, kDuplexNone)) caps.duplex_default = printing::LONG_EDGE; else caps.duplex_default = printing::SIMPLEX; diff --git a/skia/ext/image_operations_bench.cc b/skia/ext/image_operations_bench.cc index 4fd81bc0b331f..b5464c64d37f7 100644 --- a/skia/ext/image_operations_bench.cc +++ b/skia/ext/image_operations_bench.cc @@ -50,7 +50,7 @@ const StringMethodPair resize_methods[] = { bool StringToMethod(const std::string& arg, skia::ImageOperations::ResizeMethod* method) { for (size_t i = 0; i < arraysize(resize_methods); ++i) { - if (base::strcasecmp(arg.c_str(), resize_methods[i].name) == 0) { + if (base::EqualsCaseInsensitiveASCII(arg, resize_methods[i].name)) { *method = resize_methods[i].method; return true; } diff --git a/sql/connection.cc b/sql/connection.cc index d1b104908c988..d07d425eb1721 100644 --- a/sql/connection.cc +++ b/sql/connection.cc @@ -992,7 +992,8 @@ bool Connection::DoesColumnExist(const char* table_name, return false; while (statement.Step()) { - if (!base::strcasecmp(statement.ColumnString(1).c_str(), column_name)) + if (base::EqualsCaseInsensitiveASCII(statement.ColumnString(1), + column_name)) return true; } return false; diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc index c98db86484c1a..42736c9fbfa69 100644 --- a/tools/gn/filesystem_utils.cc +++ b/tools/gn/filesystem_utils.cc @@ -83,7 +83,7 @@ bool AreAbsoluteWindowsPathsEqual(const base::StringPiece& a, return false; // For now, just do a case-insensitive ASCII comparison. We could convert to - // UTF-16 and use ICU if necessary. Or maybe base::strcasecmp is good enough? + // UTF-16 and use ICU if necessary. for (size_t i = 0; i < a.size(); i++) { if (NormalizeWindowsPathChar(a[i]) != NormalizeWindowsPathChar(b[i])) return false; diff --git a/ui/base/l10n/l10n_util.cc b/ui/base/l10n/l10n_util.cc index 4182f42ec6d46..0ef20ba41b235 100644 --- a/ui/base/l10n/l10n_util.cc +++ b/ui/base/l10n/l10n_util.cc @@ -205,7 +205,7 @@ bool IsDuplicateName(const std::string& locale_name) { return !base::EndsWith(locale_name, "419", true); for (size_t i = 0; i < arraysize(kDuplicateNames); ++i) { - if (base::strcasecmp(kDuplicateNames[i], locale_name.c_str()) == 0) + if (base::EqualsCaseInsensitiveASCII(kDuplicateNames[i], locale_name)) return true; } return false; diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc index 543c62596bc19..775fb1c38c577 100644 --- a/ui/gfx/render_text_harfbuzz.cc +++ b/ui/gfx/render_text_harfbuzz.cc @@ -530,7 +530,7 @@ class HarfBuzzLineBreaker { // Function object for case insensitive string comparison. struct CaseInsensitiveCompare { bool operator() (const std::string& a, const std::string& b) const { - return base::strncasecmp(a.c_str(), b.c_str(), b.length()) < 0; + return base::CompareCaseInsensitiveASCII(a, b) < 0; } }; diff --git a/ui/gfx/test/fontconfig_util_linux.cc b/ui/gfx/test/fontconfig_util_linux.cc index e2f5140b682cf..609a3fca8bdae 100644 --- a/ui/gfx/test/fontconfig_util_linux.cc +++ b/ui/gfx/test/fontconfig_util_linux.cc @@ -100,8 +100,7 @@ bool LoadFontIntoFontconfig(const base::FilePath& path) { bool LoadSystemFontIntoFontconfig(const std::string& basename) { for (size_t i = 0; i < kNumSystemFontsForFontconfig; ++i) { base::FilePath path(kSystemFontsForFontconfig[i]); - if (base::strcasecmp(path.BaseName().value().c_str(), basename.c_str()) == - 0) + if (base::EqualsCaseInsensitiveASCII(path.BaseName().value(), basename)) return LoadFontIntoFontconfig(path); } LOG(ERROR) << "Unable to find system font named " << basename;