diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx index 5860b5ddd..4fc7145da 100644 --- a/src/SongFilter.cxx +++ b/src/SongFilter.cxx @@ -23,12 +23,12 @@ #include "DetachedSong.hxx" #include "tag/Tag.hxx" #include "util/ConstBuffer.hxx" +#include "util/StringAPI.hxx" #include "util/ASCII.hxx" #include "util/UriUtil.hxx" #include "lib/icu/Collate.hxx" #include -#include #include #define LOCATE_TAG_FILE_KEY "file" @@ -55,12 +55,12 @@ locate_parse_type(const char *str) } gcc_pure -static std::string +static AllocatedString<> ImportString(const char *p, bool fold_case) { return fold_case ? IcuCaseFold(p) - : std::string(p); + : AllocatedString<>::Duplicate(p); } SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case) @@ -70,7 +70,7 @@ SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case) } SongFilter::Item::Item(unsigned _tag, time_t _time) - :tag(_tag), time(_time) + :tag(_tag), value(nullptr), time(_time) { } @@ -85,10 +85,11 @@ SongFilter::Item::StringMatch(const char *s) const assert(tag != LOCATE_TAG_MODIFIED_SINCE); if (fold_case) { - const std::string folded = IcuCaseFold(s); - return folded.find(value) != folded.npos; + const auto folded = IcuCaseFold(s); + assert(!folded.IsNull()); + return StringFind(folded.c_str(), value.c_str()) != nullptr; } else { - return s == value; + return StringIsEqual(s, value.c_str()); } } diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx index ba5433df8..e15f0338f 100644 --- a/src/SongFilter.hxx +++ b/src/SongFilter.hxx @@ -20,10 +20,10 @@ #ifndef MPD_SONG_FILTER_HXX #define MPD_SONG_FILTER_HXX +#include "util/AllocatedString.hxx" #include "Compiler.h" #include -#include #include #include @@ -51,7 +51,7 @@ public: bool fold_case; - std::string value; + AllocatedString<> value; /** * For #LOCATE_TAG_MODIFIED_SINCE diff --git a/src/fs/Charset.cxx b/src/fs/Charset.cxx index b478959d0..f0fc1063c 100644 --- a/src/fs/Charset.cxx +++ b/src/fs/Charset.cxx @@ -116,7 +116,11 @@ PathToUTF8(PathTraitsFS::const_pointer path_fs) return FixSeparators(path_fs); #ifdef HAVE_FS_CHARSET - return FixSeparators(fs_converter->ToUTF8(path_fs)); + const auto buffer = fs_converter->ToUTF8(path_fs); + if (buffer.IsNull()) + return PathTraitsUTF8::string(); + + return FixSeparators(PathTraitsUTF8::string(buffer.c_str())); #endif #endif } @@ -141,7 +145,11 @@ PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8) if (fs_converter == nullptr) return path_utf8; - return fs_converter->FromUTF8(path_utf8); + const auto buffer = fs_converter->FromUTF8(path_utf8); + if (buffer.IsNull()) + return PathTraitsFS::string(); + + return PathTraitsFS::string(buffer.c_str()); #endif } diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx index 207252935..0df305130 100644 --- a/src/lib/icu/Collate.cxx +++ b/src/lib/icu/Collate.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "Collate.hxx" +#include "util/AllocatedString.hxx" #ifdef HAVE_ICU #include "Util.hxx" @@ -140,7 +141,7 @@ IcuCollate(const char *a, const char *b) #endif } -std::string +AllocatedString<> IcuCaseFold(const char *src) { #ifdef HAVE_ICU @@ -152,7 +153,7 @@ IcuCaseFold(const char *src) const auto u = UCharFromUTF8(src); if (u.IsNull()) - return std::string(src); + return AllocatedString<>::Duplicate(src); size_t folded_capacity = u.size * 2u; UChar *folded = new UChar[folded_capacity]; @@ -165,20 +166,17 @@ IcuCaseFold(const char *src) delete[] u.data; if (folded_length == 0 || error_code != U_ZERO_ERROR) { delete[] folded; - return std::string(src); + return AllocatedString<>::Duplicate(src); } - auto result2 = UCharToUTF8({folded, folded_length}); + auto result = UCharToUTF8({folded, folded_length}); delete[] folded; - if (result2.IsNull()) - return std::string(src); - - std::string result(result2.data, result2.size); - delete[] result2.data; + return result; #elif defined(HAVE_GLIB) char *tmp = g_utf8_casefold(src, -1); - std::string result(tmp); + auto result = AllocatedString<>::Duplicate(tmp); g_free(tmp); + return result; #else size_t size = strlen(src) + 1; auto buffer = new char[size]; @@ -194,9 +192,7 @@ IcuCaseFold(const char *src) assert(nbytes < size); assert(buffer[nbytes] == 0); - std::string result(buffer, nbytes); - delete[] buffer; + return AllocatedString<>::Donate(buffer); #endif - return result; } diff --git a/src/lib/icu/Collate.hxx b/src/lib/icu/Collate.hxx index 9f8ea43ab..0ad3b24ff 100644 --- a/src/lib/icu/Collate.hxx +++ b/src/lib/icu/Collate.hxx @@ -26,6 +26,7 @@ #include class Error; +template class AllocatedString; bool IcuCollateInit(Error &error); @@ -38,7 +39,7 @@ int IcuCollate(const char *a, const char *b); gcc_pure gcc_nonnull_all -std::string +AllocatedString IcuCaseFold(const char *src); #endif diff --git a/src/lib/icu/Converter.cxx b/src/lib/icu/Converter.cxx index ea10a9a03..fad1f4d66 100644 --- a/src/lib/icu/Converter.cxx +++ b/src/lib/icu/Converter.cxx @@ -22,6 +22,7 @@ #include "Error.hxx" #include "util/Error.hxx" #include "util/Macros.hxx" +#include "util/AllocatedString.hxx" #include "util/WritableBuffer.hxx" #include "util/ConstBuffer.hxx" @@ -80,7 +81,7 @@ IcuConverter::Create(const char *charset, Error &error) #ifdef HAVE_ICU #elif defined(HAVE_GLIB) -static std::string +static AllocatedString DoConvert(GIConv conv, const char *src) { // TODO: dynamic buffer? @@ -93,14 +94,14 @@ DoConvert(GIConv conv, const char *src) size_t n = g_iconv(conv, &in, &in_left, &out, &out_left); if (n == static_cast(-1) || in_left > 0) - return std::string(); + return nullptr; - return std::string(buffer, sizeof(buffer) - out_left); + return AllocatedString::Duplicate(buffer, sizeof(buffer) - out_left); } #endif -std::string +AllocatedString IcuConverter::ToUTF8(const char *s) const { #ifdef HAVE_ICU @@ -118,23 +119,16 @@ IcuConverter::ToUTF8(const char *s) const &source, source + strlen(source), nullptr, true, &code); if (code != U_ZERO_ERROR) - return std::string(); + return nullptr; const size_t target_length = target - buffer; - const auto u = UCharToUTF8({buffer, target_length}); - if (u.IsNull()) - return std::string(); - - std::string result(u.data, u.size); - delete[] u.data; - return result; - + return UCharToUTF8({buffer, target_length}); #elif defined(HAVE_GLIB) return DoConvert(to_utf8, s); #endif } -std::string +AllocatedString IcuConverter::FromUTF8(const char *s) const { #ifdef HAVE_ICU @@ -142,7 +136,7 @@ IcuConverter::FromUTF8(const char *s) const const auto u = UCharFromUTF8(s); if (u.IsNull()) - return std::string(); + return nullptr; ucnv_resetFromUnicode(converter); @@ -157,9 +151,9 @@ IcuConverter::FromUTF8(const char *s) const delete[] u.data; if (code != U_ZERO_ERROR) - return std::string(); + return nullptr; - return std::string(buffer, target); + return AllocatedString<>::Duplicate(buffer, target); #elif defined(HAVE_GLIB) return DoConvert(from_utf8, s); diff --git a/src/lib/icu/Converter.hxx b/src/lib/icu/Converter.hxx index 3eba86c25..fd5ea2132 100644 --- a/src/lib/icu/Converter.hxx +++ b/src/lib/icu/Converter.hxx @@ -33,14 +33,14 @@ #ifdef HAVE_ICU_CONVERTER -#include - class Error; #ifdef HAVE_ICU struct UConverter; #endif +template class AllocatedString; + /** * This class can convert strings with a certain character set to and * from UTF-8. @@ -77,17 +77,19 @@ public: /** * Convert the string to UTF-8. - * Returns empty string on error. + * + * Returns AllocatedString::Null() on error. */ gcc_pure gcc_nonnull_all - std::string ToUTF8(const char *s) const; + AllocatedString ToUTF8(const char *s) const; /** * Convert the string from UTF-8. - * Returns empty string on error. + * + * Returns AllocatedString::Null() on error. */ gcc_pure gcc_nonnull_all - std::string FromUTF8(const char *s) const; + AllocatedString FromUTF8(const char *s) const; }; #endif diff --git a/src/lib/icu/Util.cxx b/src/lib/icu/Util.cxx index ae47423ad..92f1de5aa 100644 --- a/src/lib/icu/Util.cxx +++ b/src/lib/icu/Util.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "Util.hxx" +#include "util/AllocatedString.hxx" #include "util/WritableBuffer.hxx" #include "util/ConstBuffer.hxx" @@ -49,7 +50,7 @@ UCharFromUTF8(const char *src) return { dest, size_t(dest_length) }; } -WritableBuffer +AllocatedString<> UCharToUTF8(ConstBuffer src) { assert(!src.IsNull()); @@ -57,7 +58,7 @@ UCharToUTF8(ConstBuffer src) /* worst-case estimate */ size_t dest_capacity = 4 * src.size; - char *dest = new char[dest_capacity]; + char *dest = new char[dest_capacity + 1]; UErrorCode error_code = U_ZERO_ERROR; int32_t dest_length; @@ -68,5 +69,6 @@ UCharToUTF8(ConstBuffer src) return nullptr; } - return { dest, size_t(dest_length) }; + dest[dest_length] = 0; + return AllocatedString<>::Donate(dest); } diff --git a/src/lib/icu/Util.hxx b/src/lib/icu/Util.hxx index f26b72494..f2d99d0e6 100644 --- a/src/lib/icu/Util.hxx +++ b/src/lib/icu/Util.hxx @@ -26,6 +26,7 @@ template struct WritableBuffer; template struct ConstBuffer; +template class AllocatedString; /** * Wrapper for u_strFromUTF8(). The returned pointer must be freed @@ -38,7 +39,7 @@ UCharFromUTF8(const char *src); * Wrapper for u_strToUTF8(). The returned pointer must be freed with * delete[]. */ -WritableBuffer +AllocatedString UCharToUTF8(ConstBuffer src); #endif diff --git a/test/TestIcu.cxx b/test/TestIcu.cxx index 9d525d698..484af4f22 100644 --- a/test/TestIcu.cxx +++ b/test/TestIcu.cxx @@ -4,6 +4,8 @@ #include "config.h" #include "lib/icu/Converter.hxx" +#include "util/AllocatedString.hxx" +#include "util/StringAPI.hxx" #include "util/Error.hxx" #include @@ -49,15 +51,17 @@ public: for (const auto i : invalid_utf8) { auto f = converter->FromUTF8(i); - CPPUNIT_ASSERT_EQUAL(true, f.empty()); + CPPUNIT_ASSERT_EQUAL(true, f.IsNull()); } for (const auto i : latin1_tests) { auto f = converter->FromUTF8(i.utf8); - CPPUNIT_ASSERT_EQUAL(true, f == i.other); + CPPUNIT_ASSERT_EQUAL(true, StringIsEqual(f.c_str(), + i.other)); auto t = converter->ToUTF8(i.other); - CPPUNIT_ASSERT_EQUAL(true, t == i.utf8); + CPPUNIT_ASSERT_EQUAL(true, StringIsEqual(t.c_str(), + i.utf8)); } delete converter;