From a5b7cbe3318e316b14b06334c26800f46ac26f3d Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Mon, 1 Feb 2010 04:20:01 +0000 Subject: [PATCH] Adding utf-8 aware version of most functions to BString. They are named after the corresponding normal functions but have a "Chars" in the name like "MoveCharsInto" or "AppendChars". Also added CountBytes() and CharAt(). This should make everyday string handling with multibyte strings a bit easier. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35371 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/support/String.h | 78 +++++++- src/kits/support/Jamfile | 2 +- src/kits/support/String.cpp | 352 +++++++++++++++++++++++++++++++++--- 3 files changed, 405 insertions(+), 27 deletions(-) diff --git a/headers/os/support/String.h b/headers/os/support/String.h index cb88b17230..6a790f3019 100644 --- a/headers/os/support/String.h +++ b/headers/os/support/String.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009, Haiku Inc. All Rights Reserved. + * Copyright 2001-2010, Haiku Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef __BSTRING__ @@ -26,6 +26,8 @@ public: const char* String() const; int32 Length() const; int32 CountChars() const; + int32 CountBytes(int32 fromCharOffset, + int32 charCount) const; // Assignment BString& operator=(const BString& string); @@ -43,12 +45,21 @@ public: BString& SetTo(char c, int32 count); + BString& SetToChars(const char* string, int32 charCount); + BString& SetToChars(const BString& string, int32 charCount); + BString& AdoptChars(BString& from, int32 charCount); + // Substring copying BString& CopyInto(BString& into, int32 fromOffset, int32 length) const; void CopyInto(char* into, int32 fromOffset, int32 length) const; + BString& CopyCharsInto(BString& into, int32 fromCharOffset, + int32 charCount) const; + bool CopyCharsInto(char* into, int32* intoLength, + int32 fromCharOffset, int32 charCount) const; + // Appending BString& operator+=(const BString& string); BString& operator+=(const char* string); @@ -61,6 +72,9 @@ public: BString& Append(const char* string, int32 length); BString& Append(char c, int32 count); + BString& AppendChars(const BString& string, int32 charCount); + BString& AppendChars(const char* string, int32 charCount); + // Prepending BString& Prepend(const char* string); BString& Prepend(const BString& string); @@ -68,6 +82,10 @@ public: BString& Prepend(const BString& string, int32 length); BString& Prepend(char c, int32 count); + BString& PrependChars(const char* string, int32 charCount); + BString& PrependChars(const BString& string, + int32 charCount); + // Inserting BString& Insert(const char* string, int32 position); BString& Insert(const char* string, int32 length, @@ -81,9 +99,26 @@ public: int32 length, int32 position); BString& Insert(char c, int32 count, int32 position); + BString& InsertChars(const char* string, int32 charPosition); + BString& InsertChars(const char* string, int32 charCount, + int32 charPosition); + BString& InsertChars(const char* string, + int32 fromCharOffset, int32 charCount, + int32 charPosition); + BString& InsertChars(const BString& string, + int32 charPosition); + BString& InsertChars(const BString& string, int32 charCount, + int32 charPosition); + BString& InsertChars(const BString& string, + int32 fromCharOffset, int32 charCount, + int32 charPosition); + // Removing BString& Truncate(int32 newLength, bool lazy = true); + BString& TruncateChars(int32 newCharCount, bool lazy = true); + BString& Remove(int32 from, int32 length); + BString& RemoveChars(int32 fromCharOffset, int32 charCount); BString& RemoveFirst(const BString& string); BString& RemoveLast(const BString& string); @@ -93,11 +128,17 @@ public: BString& RemoveLast(const char* string); BString& RemoveAll(const char* string); - BString& RemoveSet(const char* setOfCharsToRemove); + BString& RemoveSet(const char* setOfBytesToRemove); + BString& RemoveCharsSet(const char* setOfCharsToRemove); BString& MoveInto(BString& into, int32 from, int32 length); void MoveInto(char* into, int32 from, int32 length); + BString& MoveCharsInto(BString& into, int32 fromCharOffset, + int32 charCount); + bool MoveCharsInto(char* into, int32* intoLength, + int32 fromCharOffset, int32 charCount); + // Compare functions bool operator<(const BString& string) const; bool operator<=(const BString& string) const; @@ -120,6 +161,12 @@ public: int Compare(const char* string) const; int Compare(const BString& string, int32 length) const; int Compare(const char* string, int32 length) const; + + int CompareChars(const BString& string, + int32 charCount) const; + int CompareChars(const char* string, + int32 charCount) const; + int ICompare(const BString& string) const; int ICompare(const char* string) const; int ICompare(const BString& string, int32 length) const; @@ -135,6 +182,11 @@ public: int32 FindFirst(char c) const; int32 FindFirst(char c, int32 fromOffset) const; + int32 FindFirstChars(const BString& string, + int32 fromCharOffset) const; + int32 FindFirstChars(const char* string, + int32 fromCharOffset) const; + int32 FindLast(const BString& string) const; int32 FindLast(const char* string) const; int32 FindLast(const BString& string, @@ -144,6 +196,11 @@ public: int32 FindLast(char c) const; int32 FindLast(char c, int32 beforeOffset) const; + int32 FindLastChars(const BString& string, + int32 beforeCharOffset) const; + int32 FindLastChars(const char* string, + int32 beforeCharOffset) const; + int32 IFindFirst(const BString& string) const; int32 IFindFirst(const char* string) const; int32 IFindFirst(const BString& string, @@ -175,6 +232,12 @@ public: const char* withThis, int32 maxReplaceCount, int32 fromOffset = 0); + BString& ReplaceAllChars(const char* replaceThis, + const char* withThis, int32 fromCharOffset); + BString& ReplaceChars(const char* replaceThis, + const char* withThis, int32 maxReplaceCount, + int32 fromCharOffset); + BString& IReplaceFirst(char replaceThis, char withThis); BString& IReplaceLast(char replaceThis, char withThis); BString& IReplaceAll(char replaceThis, char withThis, @@ -191,8 +254,12 @@ public: const char* withThis, int32 maxReplaceCount, int32 fromOffset = 0); - BString& ReplaceSet(const char* setOfChars, char with); - BString& ReplaceSet(const char* setOfChars, const char* with); + BString& ReplaceSet(const char* setOfBytes, char with); + BString& ReplaceSet(const char* setOfBytes, + const char* with); + + BString& ReplaceCharsSet(const char* setOfChars, + const char* with); // Unchecked char access char operator[](int32 index) const; @@ -205,6 +272,9 @@ public: // Checked char access char ByteAt(int32 index) const; + const char* CharAt(int32 charIndex, int32* bytes = NULL) const; + bool CharAt(int32 charIndex, char* buffer, + int32* bytes) const; // Fast low-level manipulation char* LockBuffer(int32 maxLength); diff --git a/src/kits/support/Jamfile b/src/kits/support/Jamfile index 04e85de9fa..4d6ead789e 100644 --- a/src/kits/support/Jamfile +++ b/src/kits/support/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src kits support ; SetSubDirSupportedPlatforms haiku libbe_test ; -UsePrivateHeaders shared app media support ; +UsePrivateHeaders app interface media shared support ; MergeObject support_kit.o : Archivable.cpp diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp index 72d8a57aac..8fe546d28e 100644 --- a/src/kits/support/String.cpp +++ b/src/kits/support/String.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2001-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -8,6 +8,7 @@ * Oliver Tappe (openbeos@hirschkaefer.de) * Axel Dörfler, axeld@pinc-software.de * Julun + * Michael Lotz */ @@ -23,6 +24,8 @@ #include +#include + // define proper names for case-option of _DoReplace() #define KEEP_CASE false @@ -268,19 +271,15 @@ BString::~BString() int32 BString::CountChars() const { - int32 count = 0; + return UTF8CountChars(fPrivateData, Length()); +} - const char* start = fPrivateData; - const char* end = fPrivateData + Length(); - while (start++ != end) { - count++; - - // Jump to next UTF8 character - for (; (*start & 0xc0) == 0x80; start++); - } - - return count; +int32 +BString::CountBytes(int32 fromCharOffset, int32 charCount) const +{ + return UTF8CountBytes( + fPrivateData + UTF8CountBytes(fPrivateData, fromCharOffset), charCount); } @@ -404,6 +403,27 @@ BString::SetTo(char c, int32 count) } +BString& +BString::SetToChars(const char* string, int32 charCount) +{ + return SetTo(string, UTF8CountBytes(string, charCount)); +} + + +BString& +BString::SetToChars(const BString& string, int32 charCount) +{ + return SetTo(string, UTF8CountBytes(string.String(), charCount)); +} + + +BString& +BString::AdoptChars(BString& string, int32 charCount) +{ + return Adopt(string, UTF8CountBytes(string.String(), charCount)); +} + + // #pragma mark - Substring copying @@ -426,6 +446,38 @@ BString::CopyInto(char* into, int32 fromOffset, int32 length) const } +BString& +BString::CopyCharsInto(BString& into, int32 fromCharOffset, + int32 charCount) const +{ + int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset); + int32 length = UTF8CountBytes(fPrivateData + fromOffset, charCount); + return CopyInto(into, fromOffset, length); +} + + +bool +BString::CopyCharsInto(char* into, int32* intoLength, int32 fromCharOffset, + int32 charCount) const +{ + if (into == NULL) + return false; + + int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset); + int32 length = UTF8CountBytes(fPrivateData + fromOffset, charCount); + length = min_clamp0(length, Length() - fromOffset); + + if (intoLength != NULL) { + if (*intoLength < length) + return false; + *intoLength = length; + } + + memcpy(into, fPrivateData + fromOffset, length); + return true; +} + + // #pragma mark - Appending @@ -483,6 +535,20 @@ BString::Append(char c, int32 count) } +BString& +BString::AppendChars(const BString& string, int32 charCount) +{ + return Append(string, UTF8CountBytes(string.String(), charCount)); +} + + +BString& +BString::AppendChars(const char* string, int32 charCount) +{ + return Append(string, UTF8CountBytes(string, charCount)); +} + + // #pragma mark - Prepending @@ -531,6 +597,20 @@ BString::Prepend(char c, int32 count) } +BString& +BString::PrependChars(const char* string, int32 charCount) +{ + return Prepend(string, UTF8CountBytes(string, charCount)); +} + + +BString& +BString::PrependChars(const BString& string, int32 charCount) +{ + return Prepend(string, UTF8CountBytes(string.String(), charCount)); +} + + // #pragma mark - Inserting @@ -626,6 +706,58 @@ BString::Insert(char c, int32 count, int32 position) } +BString& +BString::InsertChars(const char* string, int32 charPosition) +{ + return Insert(string, UTF8CountBytes(fPrivateData, charPosition)); +} + + +BString& +BString::InsertChars(const char* string, int32 charCount, int32 charPosition) +{ + return Insert(string, UTF8CountBytes(string, charCount), + UTF8CountBytes(fPrivateData, charPosition)); +} + + +BString& +BString::InsertChars(const char* string, int32 fromCharOffset, + int32 charCount, int32 charPosition) +{ + int32 fromOffset = UTF8CountBytes(string, fromCharOffset); + return Insert(string, fromOffset, + UTF8CountBytes(string + fromOffset, charCount), + UTF8CountBytes(fPrivateData, charPosition)); +} + + +BString& +BString::InsertChars(const BString& string, int32 charPosition) +{ + return Insert(string, UTF8CountBytes(fPrivateData, charPosition)); +} + + +BString& +BString::InsertChars(const BString& string, int32 charCount, int32 charPosition) +{ + return Insert(string, UTF8CountBytes(string.String(), charCount), + UTF8CountBytes(fPrivateData, charPosition)); +} + + +BString& +BString::InsertChars(const BString& string, int32 fromCharOffset, + int32 charCount, int32 charPosition) +{ + int32 fromOffset = UTF8CountBytes(string.String(), fromCharOffset); + return Insert(string, fromOffset, + UTF8CountBytes(string.String() + fromOffset, charCount), + UTF8CountBytes(fPrivateData, charPosition)); +} + + // #pragma mark - Removing @@ -644,6 +776,13 @@ BString::Truncate(int32 newLength, bool lazy) } +BString& +BString::TruncateChars(int32 newCharCount, bool lazy) +{ + return Truncate(UTF8CountBytes(fPrivateData, newCharCount)); +} + + BString& BString::Remove(int32 from, int32 length) { @@ -653,6 +792,15 @@ BString::Remove(int32 from, int32 length) } +BString& +BString::RemoveChars(int32 fromCharOffset, int32 charCount) +{ + int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset); + return Remove(fromOffset, + UTF8CountBytes(fPrivateData + fromOffset, charCount)); +} + + BString& BString::RemoveFirst(const BString& string) { @@ -729,9 +877,16 @@ BString::RemoveAll(const char* string) BString& -BString::RemoveSet(const char* setOfCharsToRemove) +BString::RemoveSet(const char* setOfBytesToRemove) { - return ReplaceSet(setOfCharsToRemove, ""); + return ReplaceSet(setOfBytesToRemove, ""); +} + + +BString& +BString::RemoveCharsSet(const char* setOfCharsToRemove) +{ + return ReplaceCharsSet(setOfCharsToRemove, ""); } @@ -756,6 +911,30 @@ BString::MoveInto(char* into, int32 from, int32 length) } +BString& +BString::MoveCharsInto(BString& into, int32 fromCharOffset, int32 charCount) +{ + if (charCount > 0) { + CopyCharsInto(into, fromCharOffset, charCount); + RemoveChars(fromCharOffset, charCount); + } + + return into; +} + + +bool +BString::MoveCharsInto(char* into, int32* intoLength, int32 fromCharOffset, + int32 charCount) +{ + if (!CopyCharsInto(into, intoLength, fromCharOffset, charCount)) + return false; + + RemoveChars(fromCharOffset, charCount); + return true; +} + + // #pragma mark - Compare functions @@ -825,6 +1004,20 @@ BString::Compare(const char* string, int32 length) const } +int +BString::CompareChars(const BString& string, int32 charCount) const +{ + return Compare(string, UTF8CountBytes(fPrivateData, charCount)); +} + + +int +BString::CompareChars(const char* string, int32 charCount) const +{ + return Compare(string, UTF8CountBytes(fPrivateData, charCount)); +} + + int BString::ICompare(const BString& string) const { @@ -939,6 +1132,20 @@ BString::FindFirst(char c, int32 fromOffset) const } +int32 +BString::FindFirstChars(const BString& string, int32 fromCharOffset) const +{ + return FindFirst(string, UTF8CountBytes(fPrivateData, fromCharOffset)); +} + + +int32 +BString::FindFirstChars(const char* string, int32 fromCharOffset) const +{ + return FindFirst(string, UTF8CountBytes(fPrivateData, fromCharOffset)); +} + + int32 BString::FindLast(const BString& string) const { @@ -1022,6 +1229,20 @@ BString::FindLast(char c, int32 beforeOffset) const } +int32 +BString::FindLastChars(const BString& string, int32 beforeCharOffset) const +{ + return FindLast(string, UTF8CountBytes(fPrivateData, beforeCharOffset)); +} + + +int32 +BString::FindLastChars(const char* string, int32 beforeCharOffset) const +{ + return FindLast(string, UTF8CountBytes(fPrivateData, beforeCharOffset)); +} + + int32 BString::IFindFirst(const BString& string) const { @@ -1244,6 +1465,24 @@ BString::Replace(const char* replaceThis, const char* withThis, } +BString& +BString::ReplaceAllChars(const char* replaceThis, const char* withThis, + int32 fromCharOffset) +{ + return ReplaceAll(replaceThis, withThis, + UTF8CountBytes(fPrivateData, fromCharOffset)); +} + + +BString& +BString::ReplaceChars(const char* replaceThis, const char* withThis, + int32 maxReplaceCount, int32 fromCharOffset) +{ + return Replace(replaceThis, withThis, maxReplaceCount, + UTF8CountBytes(fPrivateData, fromCharOffset)); +} + + BString& BString::IReplaceFirst(char replaceThis, char withThis) { @@ -1385,9 +1624,9 @@ BString::IReplace(const char* replaceThis, const char* withThis, BString& -BString::ReplaceSet(const char* setOfChars, char with) +BString::ReplaceSet(const char* setOfBytes, char with) { - if (!setOfChars || strcspn(fPrivateData, setOfChars) >= uint32(Length())) + if (!setOfBytes || strcspn(fPrivateData, setOfBytes) >= uint32(Length())) return *this; if (_MakeWritable() != B_OK) @@ -1396,7 +1635,7 @@ BString::ReplaceSet(const char* setOfChars, char with) int32 offset = 0; int32 length = Length(); for (int32 pos;;) { - pos = strcspn(fPrivateData + offset, setOfChars); + pos = strcspn(fPrivateData + offset, setOfBytes); offset += pos; if (offset >= length) @@ -1411,16 +1650,16 @@ BString::ReplaceSet(const char* setOfChars, char with) BString& -BString::ReplaceSet(const char* setOfChars, const char* with) +BString::ReplaceSet(const char* setOfBytes, const char* with) { - if (!setOfChars || !with - || strcspn(fPrivateData, setOfChars) >= uint32(Length())) + if (!setOfBytes || !with + || strcspn(fPrivateData, setOfBytes) >= uint32(Length())) return *this; // delegate simple case int32 withLen = strlen(with); if (withLen == 1) - return ReplaceSet(setOfChars, *with); + return ReplaceSet(setOfBytes, *with); if (_MakeWritable() != B_OK) return *this; @@ -1431,7 +1670,7 @@ BString::ReplaceSet(const char* setOfChars, const char* with) PosVect positions; for (int32 offset = 0; offset < len; offset += (pos + searchLen)) { - pos = strcspn(fPrivateData + offset, setOfChars); + pos = strcspn(fPrivateData + offset, setOfBytes); if (pos + offset >= len) break; if (!positions.Add(offset + pos)) @@ -1443,6 +1682,49 @@ BString::ReplaceSet(const char* setOfChars, const char* with) } +BString& +BString::ReplaceCharsSet(const char* setOfChars, const char* with) +{ + if (!setOfChars || !with) + return *this; + + int32 setCharCount = UTF8CountChars(setOfChars, -1); + if ((uint32)setCharCount == strlen(setOfChars)) { + // no multi-byte chars at all + return ReplaceSet(setOfChars, with); + } + + BString setString(setOfChars); + BString result; + + int32 withLength = withLength; + int32 charCount = CountChars(); + for (int32 i = 0; i < charCount; i++) { + int32 charLength; + const char* sourceChar = CharAt(i, &charLength); + bool match = false; + + for (int32 j = 0; j < setCharCount; j++) { + int32 setCharLength; + const char* setChar = setString.CharAt(j, &setCharLength); + if (charLength == setCharLength + && memcmp(sourceChar, setChar, charLength) == 0) { + match = true; + break; + } + } + + if (match) + result.Append(with, withLength); + else + result.Append(sourceChar, charLength); + } + + *this = result; + return *this; +} + + // #pragma mark - Unchecked char access @@ -1469,6 +1751,32 @@ BString::operator[](int32 index) #endif +const char* +BString::CharAt(int32 charIndex, int32* bytes) const +{ + int32 offset = UTF8CountBytes(fPrivateData, charIndex); + if (bytes != NULL) + *bytes = UTF8NextCharLen(fPrivateData + offset); + return fPrivateData + offset; +} + + +bool +BString::CharAt(int32 charIndex, char* buffer, int32* bytes) const +{ + int32 length; + const char* charAt = CharAt(charIndex, &length); + if (bytes != NULL) { + if (*bytes < length) + return false; + *bytes = length; + } + + memcpy(buffer, charAt, length); + return true; +} + + // #pragma mark - Fast low-level manipulation