From 1facf851b063d0c0f0821aae76b0689927967aa4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 16 Jan 2026 22:47:33 -1000 Subject: [PATCH 1/2] wip --- esphome/components/audio/audio_reader.cpp | 8 +++----- esphome/core/helpers.cpp | 6 ++++++ esphome/core/helpers.h | 13 +++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/esphome/components/audio/audio_reader.cpp b/esphome/components/audio/audio_reader.cpp index 7794187a69..4e4bd31f9b 100644 --- a/esphome/components/audio/audio_reader.cpp +++ b/esphome/components/audio/audio_reader.cpp @@ -185,18 +185,16 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) { return err; } - std::string url_string = str_lower_case(url); - - if (str_endswith(url_string, ".wav")) { + if (str_endswith_ignore_case(url, ".wav")) { file_type = AudioFileType::WAV; } #ifdef USE_AUDIO_MP3_SUPPORT - else if (str_endswith(url_string, ".mp3")) { + else if (str_endswith_ignore_case(url, ".mp3")) { file_type = AudioFileType::MP3; } #endif #ifdef USE_AUDIO_FLAC_SUPPORT - else if (str_endswith(url_string, ".flac")) { + else if (str_endswith_ignore_case(url, ".flac")) { file_type = AudioFileType::FLAC; } #endif diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 5de1c70562..432bf5d28a 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -174,6 +174,12 @@ bool str_endswith(const std::string &str, const std::string &end) { return str.rfind(end) == (str.size() - end.size()); } #endif + +bool str_endswith_ignore_case(const char *str, size_t str_len, const char *suffix, size_t suffix_len) { + if (suffix_len > str_len) + return false; + return strncasecmp(str + str_len - suffix_len, suffix, suffix_len) == 0; +} std::string str_truncate(const std::string &str, size_t length) { return str.length() > length ? str.substr(0, length) : str; } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 0acc6bdc60..d5941e40f6 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -517,12 +517,25 @@ template constexpr T convert_little_endian(T val) { bool str_equals_case_insensitive(const std::string &a, const std::string &b); /// Compare StringRefs for equality in case-insensitive manner. bool str_equals_case_insensitive(StringRef a, StringRef b); +/// Compare C strings for equality in case-insensitive manner (no heap allocation). +inline bool str_equals_case_insensitive(const char *a, const char *b) { return strcasecmp(a, b) == 0; } +inline bool str_equals_case_insensitive(const std::string &a, const char *b) { return strcasecmp(a.c_str(), b) == 0; } +inline bool str_equals_case_insensitive(const char *a, const std::string &b) { return strcasecmp(a, b.c_str()) == 0; } /// Check whether a string starts with a value. bool str_startswith(const std::string &str, const std::string &start); /// Check whether a string ends with a value. bool str_endswith(const std::string &str, const std::string &end); +/// Case-insensitive check if string ends with suffix (no heap allocation). +bool str_endswith_ignore_case(const char *str, size_t str_len, const char *suffix, size_t suffix_len); +inline bool str_endswith_ignore_case(const char *str, const char *suffix) { + return str_endswith_ignore_case(str, strlen(str), suffix, strlen(suffix)); +} +inline bool str_endswith_ignore_case(const std::string &str, const char *suffix) { + return str_endswith_ignore_case(str.c_str(), str.size(), suffix, strlen(suffix)); +} + /// Truncate a string to a specific length. /// @warning Allocates heap memory. Avoid in new code - causes heap fragmentation on long-running devices. std::string str_truncate(const std::string &str, size_t length); From 7f5d3894ad2b2cfcd3091a54e3131dd1eff98447 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 16 Jan 2026 22:49:00 -1000 Subject: [PATCH 2/2] remove --- esphome/components/audio/audio_reader.cpp | 8 +++++--- esphome/core/helpers.cpp | 6 ------ esphome/core/helpers.h | 9 --------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/esphome/components/audio/audio_reader.cpp b/esphome/components/audio/audio_reader.cpp index 4e4bd31f9b..7794187a69 100644 --- a/esphome/components/audio/audio_reader.cpp +++ b/esphome/components/audio/audio_reader.cpp @@ -185,16 +185,18 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) { return err; } - if (str_endswith_ignore_case(url, ".wav")) { + std::string url_string = str_lower_case(url); + + if (str_endswith(url_string, ".wav")) { file_type = AudioFileType::WAV; } #ifdef USE_AUDIO_MP3_SUPPORT - else if (str_endswith_ignore_case(url, ".mp3")) { + else if (str_endswith(url_string, ".mp3")) { file_type = AudioFileType::MP3; } #endif #ifdef USE_AUDIO_FLAC_SUPPORT - else if (str_endswith_ignore_case(url, ".flac")) { + else if (str_endswith(url_string, ".flac")) { file_type = AudioFileType::FLAC; } #endif diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 432bf5d28a..5de1c70562 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -174,12 +174,6 @@ bool str_endswith(const std::string &str, const std::string &end) { return str.rfind(end) == (str.size() - end.size()); } #endif - -bool str_endswith_ignore_case(const char *str, size_t str_len, const char *suffix, size_t suffix_len) { - if (suffix_len > str_len) - return false; - return strncasecmp(str + str_len - suffix_len, suffix, suffix_len) == 0; -} std::string str_truncate(const std::string &str, size_t length) { return str.length() > length ? str.substr(0, length) : str; } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index d5941e40f6..ee95757321 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -527,15 +527,6 @@ bool str_startswith(const std::string &str, const std::string &start); /// Check whether a string ends with a value. bool str_endswith(const std::string &str, const std::string &end); -/// Case-insensitive check if string ends with suffix (no heap allocation). -bool str_endswith_ignore_case(const char *str, size_t str_len, const char *suffix, size_t suffix_len); -inline bool str_endswith_ignore_case(const char *str, const char *suffix) { - return str_endswith_ignore_case(str, strlen(str), suffix, strlen(suffix)); -} -inline bool str_endswith_ignore_case(const std::string &str, const char *suffix) { - return str_endswith_ignore_case(str.c_str(), str.size(), suffix, strlen(suffix)); -} - /// Truncate a string to a specific length. /// @warning Allocates heap memory. Avoid in new code - causes heap fragmentation on long-running devices. std::string str_truncate(const std::string &str, size_t length);