|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-9 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
- */
-
- #ifdef _MSC_VER
- #pragma warning (disable: 4514)
- #pragma warning (push)
- #endif
- #include <locale>
-
- #include "../core/juce_StandardHeader.h"
-
- #if JUCE_MSVC
- #include <float.h>
- #endif
-
- BEGIN_JUCE_NAMESPACE
-
- #include "juce_String.h"
- #include "../core/juce_Atomic.h"
-
- #ifdef _MSC_VER
- #pragma warning (pop)
- #endif
-
- //==============================================================================
- static const char* const emptyCharString = "\0\0\0\0JUCE";
- static const int safeEmptyStringRefCount = 0x3fffffff;
- String::InternalRefCountedStringHolder String::emptyString = { safeEmptyStringRefCount, 0, { 0 } };
- static tchar decimalPoint = T('.');
-
- void juce_initialiseStrings()
- {
- decimalPoint = String::fromUTF8 ((const uint8*) localeconv()->decimal_point) [0];
- }
-
- //==============================================================================
- void String::deleteInternal() throw()
- {
- if (atomicDecrementAndReturn (text->refCount) == 0)
- juce_free (text);
- }
-
- void String::createInternal (const int numChars) throw()
- {
- jassert (numChars > 0);
-
- text = (InternalRefCountedStringHolder*) juce_malloc (sizeof (InternalRefCountedStringHolder)
- + numChars * sizeof (tchar));
- text->refCount = 1;
- text->allocatedNumChars = numChars;
- text->text[0] = 0;
- }
-
- void String::createInternal (const tchar* const t, const tchar* const textEnd) throw()
- {
- jassert (*(textEnd - 1) == 0); // must have a null terminator
-
- const int numChars = (int) (textEnd - t);
- createInternal (numChars - 1);
- memcpy (text->text, t, numChars * sizeof (tchar));
- }
-
- void String::appendInternal (const tchar* const newText,
- const int numExtraChars) throw()
- {
- if (numExtraChars > 0)
- {
- const int oldLen = CharacterFunctions::length (text->text);
- const int newTotalLen = oldLen + numExtraChars;
-
- if (text->refCount > 1)
- {
- // it's in use by other strings as well, so we need to make a private copy before messing with it..
- InternalRefCountedStringHolder* const newTextHolder
- = (InternalRefCountedStringHolder*) juce_malloc (sizeof (InternalRefCountedStringHolder)
- + newTotalLen * sizeof (tchar));
- newTextHolder->refCount = 1;
- newTextHolder->allocatedNumChars = newTotalLen;
-
- memcpy (newTextHolder->text, text->text, oldLen * sizeof (tchar));
- memcpy (newTextHolder->text + oldLen, newText, numExtraChars * sizeof (tchar));
-
- InternalRefCountedStringHolder* const old = text;
- text = newTextHolder;
-
- if (atomicDecrementAndReturn (old->refCount) == 0)
- juce_free (old);
- }
- else
- {
- // no other strings using it, so just expand it if needed..
- if (newTotalLen > text->allocatedNumChars)
- {
- text = (InternalRefCountedStringHolder*)
- juce_realloc (text, sizeof (InternalRefCountedStringHolder)
- + newTotalLen * sizeof (tchar));
-
- text->allocatedNumChars = newTotalLen;
- }
-
- memcpy (text->text + oldLen, newText, numExtraChars * sizeof (tchar));
- }
-
- text->text [newTotalLen] = 0;
- }
- }
-
- void String::dupeInternalIfMultiplyReferenced() throw()
- {
- if (text->refCount > 1)
- {
- InternalRefCountedStringHolder* const old = text;
- const int len = old->allocatedNumChars;
-
- InternalRefCountedStringHolder* const newTextHolder
- = (InternalRefCountedStringHolder*) juce_malloc (sizeof (InternalRefCountedStringHolder)
- + len * sizeof (tchar));
-
- newTextHolder->refCount = 1;
- newTextHolder->allocatedNumChars = len;
-
- memcpy (newTextHolder->text, old->text, (len + 1) * sizeof (tchar));
-
- text = newTextHolder;
-
- if (atomicDecrementAndReturn (old->refCount) == 0)
- juce_free (old);
- }
- }
-
- //==============================================================================
- const String String::empty;
-
-
- //==============================================================================
- String::String() throw()
- : text (&emptyString)
- {
- }
-
- String::String (const String& other) throw()
- : text (other.text)
- {
- atomicIncrement (text->refCount);
- }
-
- String::String (const int numChars,
- const int /*dummyVariable*/) throw()
- {
- createInternal (numChars);
- }
-
- String::String (const char* const t) throw()
- {
- if (t != 0 && *t != 0)
- {
- const int len = CharacterFunctions::length (t);
- createInternal (len);
-
- #if JUCE_STRINGS_ARE_UNICODE
- CharacterFunctions::copy (text->text, t, len + 1);
- #else
- memcpy (text->text, t, len + 1);
- #endif
- }
- else
- {
- text = &emptyString;
- emptyString.refCount = safeEmptyStringRefCount;
- }
- }
-
- String::String (const juce_wchar* const t) throw()
- {
- if (t != 0 && *t != 0)
- {
- #if JUCE_STRINGS_ARE_UNICODE
- const int len = CharacterFunctions::length (t);
- createInternal (len);
-
- memcpy (text->text, t, (len + 1) * sizeof (tchar));
- #else
- const int len = CharacterFunctions::bytesRequiredForCopy (t);
- createInternal (len);
-
- CharacterFunctions::copy (text->text, t, len + 1);
- #endif
- }
- else
- {
- text = &emptyString;
- emptyString.refCount = safeEmptyStringRefCount;
- }
- }
-
- String::String (const char* const t,
- const int maxChars) throw()
- {
- int i;
- for (i = 0; i < maxChars; ++i)
- if (t[i] == 0)
- break;
-
- if (i > 0)
- {
- createInternal (i);
-
- #if JUCE_STRINGS_ARE_UNICODE
- CharacterFunctions::copy (text->text, t, i);
- #else
- memcpy (text->text, t, i);
- #endif
-
- text->text [i] = 0;
- }
- else
- {
- text = &emptyString;
- emptyString.refCount = safeEmptyStringRefCount;
- }
- }
-
- String::String (const juce_wchar* const t,
- const int maxChars) throw()
- {
- int i;
- for (i = 0; i < maxChars; ++i)
- if (t[i] == 0)
- break;
-
- if (i > 0)
- {
- createInternal (i);
-
- #if JUCE_STRINGS_ARE_UNICODE
- memcpy (text->text, t, i * sizeof (tchar));
- #else
- CharacterFunctions::copy (text->text, t, i);
- #endif
- text->text [i] = 0;
- }
- else
- {
- text = &emptyString;
- emptyString.refCount = safeEmptyStringRefCount;
- }
- }
-
- const String String::charToString (const tchar character) throw()
- {
- tchar temp[2];
- temp[0] = character;
- temp[1] = 0;
-
- return String (temp);
- }
-
- // pass in a pointer to the END of a buffer..
- static tchar* int64ToCharString (tchar* t, const int64 n) throw()
- {
- *--t = 0;
- int64 v = (n >= 0) ? n : -n;
-
- do
- {
- *--t = (tchar) (T('0') + (int) (v % 10));
- v /= 10;
-
- } while (v > 0);
-
- if (n < 0)
- *--t = T('-');
-
- return t;
- }
-
- static tchar* intToCharString (tchar* t, const int n) throw()
- {
- if (n == (int) 0x80000000) // (would cause an overflow)
- return int64ToCharString (t, n);
-
- *--t = 0;
- int v = abs (n);
-
- do
- {
- *--t = (tchar) (T('0') + (v % 10));
- v /= 10;
-
- } while (v > 0);
-
- if (n < 0)
- *--t = T('-');
-
- return t;
- }
-
- static tchar* uintToCharString (tchar* t, unsigned int v) throw()
- {
- *--t = 0;
-
- do
- {
- *--t = (tchar) (T('0') + (v % 10));
- v /= 10;
-
- } while (v > 0);
-
- return t;
- }
-
- String::String (const int number) throw()
- {
- tchar buffer [16];
- tchar* const end = buffer + 16;
-
- createInternal (intToCharString (end, number), end);
- }
-
- String::String (const unsigned int number) throw()
- {
- tchar buffer [16];
- tchar* const end = buffer + 16;
-
- createInternal (uintToCharString (end, number), end);
- }
-
- String::String (const short number) throw()
- {
- tchar buffer [16];
- tchar* const end = buffer + 16;
-
- createInternal (intToCharString (end, (int) number), end);
- }
-
- String::String (const unsigned short number) throw()
- {
- tchar buffer [16];
- tchar* const end = buffer + 16;
-
- createInternal (uintToCharString (end, (unsigned int) number), end);
- }
-
- String::String (const int64 number) throw()
- {
- tchar buffer [32];
- tchar* const end = buffer + 32;
-
- createInternal (int64ToCharString (end, number), end);
- }
-
- String::String (const uint64 number) throw()
- {
- tchar buffer [32];
- tchar* const end = buffer + 32;
- tchar* t = end;
-
- *--t = 0;
- int64 v = number;
-
- do
- {
- *--t = (tchar) (T('0') + (int) (v % 10));
- v /= 10;
-
- } while (v > 0);
-
- createInternal (t, end);
- }
-
- // a double-to-string routine that actually uses the number of dec. places you asked for
- // without resorting to exponent notation if the number's too big or small (which is what printf does).
- void String::doubleToStringWithDecPlaces (double n, int numDecPlaces) throw()
- {
- const int bufSize = 80;
- tchar buffer [bufSize];
- int len;
- tchar* t;
-
- if (numDecPlaces > 0 && n > -1.0e20 && n < 1.0e20)
- {
- int64 v = (int64) (pow (10.0, numDecPlaces) * fabs (n) + 0.5);
-
- t = buffer + bufSize;
- *--t = (tchar) 0;
-
- while (numDecPlaces >= 0 || v > 0)
- {
- if (numDecPlaces == 0)
- *--t = decimalPoint;
-
- *--t = (tchar) (T('0') + (v % 10));
-
- v /= 10;
- --numDecPlaces;
- }
-
- if (n < 0)
- *--t = T('-');
-
- len = (int) ((buffer + bufSize) - t);
- }
- else
- {
- len = CharacterFunctions::printf (buffer, bufSize, T("%.9g"), n) + 1;
- t = buffer;
- }
-
- if (len > 1)
- {
- jassert (len < numElementsInArray (buffer));
-
- createInternal (len - 1);
- memcpy (text->text, t, len * sizeof (tchar));
- }
- else
- {
- jassert (*t == 0);
- text = &emptyString;
- emptyString.refCount = safeEmptyStringRefCount;
- }
- }
-
- String::String (const float number,
- const int numberOfDecimalPlaces) throw()
- {
- doubleToStringWithDecPlaces ((double) number,
- numberOfDecimalPlaces);
- }
-
- String::String (const double number,
- const int numberOfDecimalPlaces) throw()
- {
- doubleToStringWithDecPlaces (number,
- numberOfDecimalPlaces);
- }
-
- String::~String() throw()
- {
- emptyString.refCount = safeEmptyStringRefCount;
-
- if (atomicDecrementAndReturn (text->refCount) == 0)
- juce_free (text);
- }
-
- //==============================================================================
- void String::preallocateStorage (const int numChars) throw()
- {
- if (numChars > text->allocatedNumChars)
- {
- dupeInternalIfMultiplyReferenced();
-
- text = (InternalRefCountedStringHolder*) juce_realloc (text, sizeof (InternalRefCountedStringHolder)
- + numChars * sizeof (tchar));
- text->allocatedNumChars = numChars;
- }
- }
-
- //==============================================================================
- #if JUCE_STRINGS_ARE_UNICODE
- String::operator const char*() const throw()
- {
- if (isEmpty())
- {
- return (const char*) emptyCharString;
- }
- else
- {
- String* const mutableThis = const_cast <String*> (this);
-
- mutableThis->dupeInternalIfMultiplyReferenced();
- int len = CharacterFunctions::bytesRequiredForCopy (text->text) + 1;
- mutableThis->text = (InternalRefCountedStringHolder*)
- juce_realloc (text, sizeof (InternalRefCountedStringHolder)
- + (len * sizeof (juce_wchar) + len));
- char* otherCopy = (char*) (text->text + len);
- --len;
-
- CharacterFunctions::copy (otherCopy, text->text, len);
- otherCopy [len] = 0;
- return otherCopy;
- }
- }
-
- #else
-
- String::operator const juce_wchar*() const throw()
- {
- if (isEmpty())
- {
- return (const juce_wchar*) emptyCharString;
- }
- else
- {
- String* const mutableThis = const_cast <String*> (this);
-
- mutableThis->dupeInternalIfMultiplyReferenced();
- int len = CharacterFunctions::length (text->text) + 1;
- mutableThis->text = (InternalRefCountedStringHolder*)
- juce_realloc (text, sizeof (InternalRefCountedStringHolder)
- + (len * sizeof (juce_wchar) + len));
-
- juce_wchar* otherCopy = (juce_wchar*) (text->text + len);
- --len;
-
- CharacterFunctions::copy (otherCopy, text->text, len);
- otherCopy [len] = 0;
- return otherCopy;
- }
- }
-
- #endif
-
- void String::copyToBuffer (char* const destBuffer,
- const int bufferSizeBytes) const throw()
- {
- #if JUCE_STRINGS_ARE_UNICODE
- const int len = jmin (bufferSizeBytes, CharacterFunctions::bytesRequiredForCopy (text->text));
- CharacterFunctions::copy (destBuffer, text->text, len);
- #else
- const int len = jmin (bufferSizeBytes, length());
- memcpy (destBuffer, text->text, len * sizeof (tchar));
- #endif
-
- destBuffer [len] = 0;
- }
-
- void String::copyToBuffer (juce_wchar* const destBuffer,
- const int maxCharsToCopy) const throw()
- {
- const int len = jmin (maxCharsToCopy, length());
-
- #if JUCE_STRINGS_ARE_UNICODE
- memcpy (destBuffer, text->text, len * sizeof (juce_wchar));
- #else
- CharacterFunctions::copy (destBuffer, text->text, len);
- #endif
-
- destBuffer [len] = 0;
- }
-
- //==============================================================================
- int String::length() const throw()
- {
- return CharacterFunctions::length (text->text);
- }
-
- int String::hashCode() const throw()
- {
- const tchar* t = text->text;
- int result = 0;
-
- while (*t != (tchar) 0)
- result = 31 * result + *t++;
-
- return result;
- }
-
- int64 String::hashCode64() const throw()
- {
- const tchar* t = text->text;
- int64 result = 0;
-
- while (*t != (tchar) 0)
- result = 101 * result + *t++;
-
- return result;
- }
-
- //==============================================================================
- const String& String::operator= (const tchar* const otherText) throw()
- {
- if (otherText != 0 && *otherText != 0)
- {
- const int otherLen = CharacterFunctions::length (otherText);
-
- if (otherLen > 0)
- {
- // avoid resizing the memory block if the string is
- // shrinking..
- if (text->refCount > 1
- || otherLen > text->allocatedNumChars
- || otherLen <= (text->allocatedNumChars >> 1))
- {
- deleteInternal();
- createInternal (otherLen);
- }
-
- memcpy (text->text, otherText, (otherLen + 1) * sizeof (tchar));
-
- return *this;
- }
- }
-
- deleteInternal();
- text = &emptyString;
- emptyString.refCount = safeEmptyStringRefCount;
-
- return *this;
- }
-
- const String& String::operator= (const String& other) throw()
- {
- if (this != &other)
- {
- atomicIncrement (other.text->refCount);
-
- if (atomicDecrementAndReturn (text->refCount) == 0)
- juce_free (text);
-
- text = other.text;
- }
-
- return *this;
- }
-
- //==============================================================================
- bool String::operator== (const String& other) const throw()
- {
- return text == other.text
- || CharacterFunctions::compare (text->text, other.text->text) == 0;
- }
-
- bool String::operator== (const tchar* const t) const throw()
- {
- return t != 0 ? CharacterFunctions::compare (text->text, t) == 0
- : isEmpty();
- }
-
- bool String::equalsIgnoreCase (const tchar* t) const throw()
- {
- return t != 0 ? CharacterFunctions::compareIgnoreCase (text->text, t) == 0
- : isEmpty();
- }
-
- bool String::equalsIgnoreCase (const String& other) const throw()
- {
- return text == other.text
- || CharacterFunctions::compareIgnoreCase (text->text, other.text->text) == 0;
- }
-
- bool String::operator!= (const String& other) const throw()
- {
- return text != other.text
- && CharacterFunctions::compare (text->text, other.text->text) != 0;
- }
-
- bool String::operator!= (const tchar* const t) const throw()
- {
- return t != 0 ? (CharacterFunctions::compare (text->text, t) != 0)
- : isNotEmpty();
- }
-
- bool String::operator> (const String& other) const throw()
- {
- return compare (other) > 0;
- }
-
- bool String::operator< (const tchar* const other) const throw()
- {
- return compare (other) < 0;
- }
-
- bool String::operator>= (const String& other) const throw()
- {
- return compare (other) >= 0;
- }
-
- bool String::operator<= (const tchar* const other) const throw()
- {
- return compare (other) <= 0;
- }
-
- int String::compare (const tchar* const other) const throw()
- {
- return other != 0 ? CharacterFunctions::compare (text->text, other)
- : isEmpty();
- }
-
- int String::compareIgnoreCase (const tchar* const other) const throw()
- {
- return other != 0 ? CharacterFunctions::compareIgnoreCase (text->text, other)
- : isEmpty();
- }
-
- int String::compareLexicographically (const tchar* other) const throw()
- {
- if (other == 0)
- return isEmpty();
-
- const tchar* s1 = text->text;
- while (*s1 != 0 && ! CharacterFunctions::isLetterOrDigit (*s1))
- ++s1;
-
- while (*other != 0 && ! CharacterFunctions::isLetterOrDigit (*other))
- ++other;
-
- return CharacterFunctions::compareIgnoreCase (s1, other);
- }
-
- //==============================================================================
- const String String::operator+ (const String& other) const throw()
- {
- if (*(other.text->text) == 0)
- return *this;
-
- if (isEmpty())
- return other;
-
- const int len = CharacterFunctions::length (text->text);
- const int otherLen = CharacterFunctions::length (other.text->text);
-
- String result (len + otherLen, (int) 0);
- memcpy (result.text->text, text->text, len * sizeof (tchar));
- memcpy (result.text->text + len, other.text->text, otherLen * sizeof (tchar));
- result.text->text [len + otherLen] = 0;
-
- return result;
- }
-
- const String String::operator+ (const tchar* const textToAppend) const throw()
- {
- if (textToAppend == 0 || *textToAppend == 0)
- return *this;
-
- const int len = CharacterFunctions::length (text->text);
- const int otherLen = CharacterFunctions::length (textToAppend);
-
- String result (len + otherLen, (int) 0);
- memcpy (result.text->text, text->text, len * sizeof (tchar));
- memcpy (result.text->text + len, textToAppend, otherLen * sizeof (tchar));
- result.text->text [len + otherLen] = 0;
-
- return result;
- }
-
- const String String::operator+ (const tchar characterToAppend) const throw()
- {
- if (characterToAppend == 0)
- return *this;
-
- const int len = CharacterFunctions::length (text->text);
- String result ((int) (len + 1), (int) 0);
-
- memcpy (result.text->text, text->text, len * sizeof (tchar));
- result.text->text[len] = characterToAppend;
- result.text->text[len + 1] = 0;
-
- return result;
- }
-
- //==============================================================================
- const String JUCE_PUBLIC_FUNCTION operator+ (const char* const string1,
- const String& string2) throw()
- {
- String s (string1);
- s += string2;
- return s;
- }
-
- const String JUCE_PUBLIC_FUNCTION operator+ (const juce_wchar* const string1,
- const String& string2) throw()
- {
- String s (string1);
- s += string2;
- return s;
- }
-
- //==============================================================================
- const String& String::operator+= (const tchar* const t) throw()
- {
- if (t != 0)
- appendInternal (t, CharacterFunctions::length (t));
-
- return *this;
- }
-
- const String& String::operator+= (const String& other) throw()
- {
- if (isEmpty())
- operator= (other);
- else
- appendInternal (other.text->text,
- CharacterFunctions::length (other.text->text));
-
- return *this;
- }
-
- const String& String::operator+= (const char ch) throw()
- {
- char asString[2];
- asString[0] = ch;
- asString[1] = 0;
-
- #if JUCE_STRINGS_ARE_UNICODE
- operator+= (String (asString));
- #else
- appendInternal (asString, 1);
- #endif
-
- return *this;
- }
-
- const String& String::operator+= (const juce_wchar ch) throw()
- {
- juce_wchar asString[2];
- asString[0] = ch;
- asString[1] = 0;
-
- #if JUCE_STRINGS_ARE_UNICODE
- appendInternal (asString, 1);
- #else
- operator+= (String (asString));
- #endif
-
- return *this;
- }
-
- void String::append (const tchar* const other,
- const int howMany) throw()
- {
- if (howMany > 0)
- {
- int i;
- for (i = 0; i < howMany; ++i)
- if (other[i] == 0)
- break;
-
- appendInternal (other, i);
- }
- }
-
- String& String::operator<< (const int number) throw()
- {
- tchar buffer [64];
- tchar* const end = buffer + 64;
- const tchar* const t = intToCharString (end, number);
- appendInternal (t, (int) (end - t) - 1);
-
- return *this;
- }
-
- String& String::operator<< (const unsigned int number) throw()
- {
- tchar buffer [64];
- tchar* const end = buffer + 64;
- const tchar* const t = uintToCharString (end, number);
- appendInternal (t, (int) (end - t) - 1);
-
- return *this;
- }
-
- String& String::operator<< (const short number) throw()
- {
- tchar buffer [64];
- tchar* const end = buffer + 64;
- const tchar* const t = intToCharString (end, (int) number);
- appendInternal (t, (int) (end - t) - 1);
-
- return *this;
- }
-
- String& String::operator<< (const long number) throw()
- {
- return operator<< ((int) number);
- }
-
- String& String::operator<< (const unsigned long number) throw()
- {
- return operator<< ((unsigned int) number);
- }
-
- String& String::operator<< (const double number) throw()
- {
- operator+= (String (number));
- return *this;
- }
-
- String& String::operator<< (const float number) throw()
- {
- operator+= (String (number));
- return *this;
- }
-
- String& String::operator<< (const char character) throw()
- {
- operator+= (character);
- return *this;
- }
-
- String& String::operator<< (const juce_wchar character) throw()
- {
- operator+= (character);
- return *this;
- }
-
- String& String::operator<< (const char* const t) throw()
- {
- #if JUCE_STRINGS_ARE_UNICODE
- operator+= (String (t));
- #else
- operator+= (t);
- #endif
- return *this;
- }
-
- String& String::operator<< (const juce_wchar* const t) throw()
- {
- #if JUCE_STRINGS_ARE_UNICODE
- operator+= (t);
- #else
- operator+= (String (t));
- #endif
- return *this;
- }
-
- String& String::operator<< (const String& t) throw()
- {
- operator+= (t);
- return *this;
- }
-
- //==============================================================================
- int String::indexOfChar (const tchar character) const throw()
- {
- const tchar* t = text->text;
-
- for (;;)
- {
- if (*t == character)
- return (int) (t - text->text);
-
- if (*t++ == 0)
- return -1;
- }
- }
-
- int String::lastIndexOfChar (const tchar character) const throw()
- {
- for (int i = CharacterFunctions::length (text->text); --i >= 0;)
- if (text->text[i] == character)
- return i;
-
- return -1;
- }
-
- int String::indexOf (const tchar* const t) const throw()
- {
- const tchar* const r = CharacterFunctions::find (text->text, t);
- return (r == 0) ? -1
- : (int) (r - text->text);
- }
-
- int String::indexOfChar (const int startIndex,
- const tchar character) const throw()
- {
- if (startIndex >= 0 && startIndex >= CharacterFunctions::length (text->text))
- return -1;
-
- const tchar* t = text->text + jmax (0, startIndex);
-
- for (;;)
- {
- if (*t == character)
- return (int) (t - text->text);
-
- if (*t++ == 0)
- return -1;
- }
- }
-
- int String::indexOfAnyOf (const tchar* const charactersToLookFor,
- const int startIndex,
- const bool ignoreCase) const throw()
- {
- if (charactersToLookFor == 0
- || (startIndex >= 0 && startIndex >= CharacterFunctions::length (text->text)))
- return -1;
-
- const tchar* t = text->text + jmax (0, startIndex);
-
- while (*t != 0)
- {
- if (CharacterFunctions::indexOfChar (charactersToLookFor, *t, ignoreCase) >= 0)
- return (int) (t - text->text);
-
- ++t;
- }
-
- return -1;
- }
-
- int String::indexOf (const int startIndex,
- const tchar* const other) const throw()
- {
- if (other == 0 || startIndex >= CharacterFunctions::length (text->text))
- return -1;
-
- const tchar* const found = CharacterFunctions::find (text->text + jmax (0, startIndex),
- other);
-
- return (found == 0) ? -1
- : (int) (found - text->text);
- }
-
- int String::indexOfIgnoreCase (const tchar* const other) const throw()
- {
- if (other != 0 && *other != 0)
- {
- const int len = CharacterFunctions::length (other);
- const int end = CharacterFunctions::length (text->text) - len;
-
- for (int i = 0; i <= end; ++i)
- if (CharacterFunctions::compareIgnoreCase (text->text + i, other, len) == 0)
- return i;
- }
-
- return -1;
- }
-
- int String::indexOfIgnoreCase (const int startIndex,
- const tchar* const other) const throw()
- {
- if (other != 0 && *other != 0)
- {
- const int len = CharacterFunctions::length (other);
- const int end = length() - len;
-
- for (int i = jmax (0, startIndex); i <= end; ++i)
- if (CharacterFunctions::compareIgnoreCase (text->text + i, other, len) == 0)
- return i;
- }
-
- return -1;
- }
-
- int String::lastIndexOf (const tchar* const other) const throw()
- {
- if (other != 0 && *other != 0)
- {
- const int len = CharacterFunctions::length (other);
- int i = length() - len;
-
- if (i >= 0)
- {
- const tchar* n = text->text + i;
-
- while (i >= 0)
- {
- if (CharacterFunctions::compare (n--, other, len) == 0)
- return i;
-
- --i;
- }
- }
- }
-
- return -1;
- }
-
- int String::lastIndexOfIgnoreCase (const tchar* const other) const throw()
- {
- if (other != 0 && *other != 0)
- {
- const int len = CharacterFunctions::length (other);
- int i = length() - len;
-
- if (i >= 0)
- {
- const tchar* n = text->text + i;
-
- while (i >= 0)
- {
- if (CharacterFunctions::compareIgnoreCase (n--, other, len) == 0)
- return i;
-
- --i;
- }
- }
- }
-
- return -1;
- }
-
- int String::lastIndexOfAnyOf (const tchar* const charactersToLookFor,
- const bool ignoreCase) const throw()
- {
- for (int i = CharacterFunctions::length (text->text); --i >= 0;)
- if (CharacterFunctions::indexOfChar (charactersToLookFor, text->text [i], ignoreCase) >= 0)
- return i;
-
- return -1;
- }
-
- bool String::contains (const tchar* const other) const throw()
- {
- return indexOf (other) >= 0;
- }
-
- bool String::containsChar (const tchar character) const throw()
- {
- return indexOfChar (character) >= 0;
- }
-
- bool String::containsIgnoreCase (const tchar* const t) const throw()
- {
- return indexOfIgnoreCase (t) >= 0;
- }
-
- int String::indexOfWholeWord (const tchar* const word) const throw()
- {
- if (word != 0 && *word != 0)
- {
- const int wordLen = CharacterFunctions::length (word);
- const int end = length() - wordLen;
- const tchar* t = text->text;
-
- for (int i = 0; i <= end; ++i)
- {
- if (CharacterFunctions::compare (t, word, wordLen) == 0
- && (i == 0 || ! CharacterFunctions::isLetterOrDigit (* (t - 1)))
- && ! CharacterFunctions::isLetterOrDigit (t [wordLen]))
- {
- return i;
- }
-
- ++t;
- }
- }
-
- return -1;
- }
-
- int String::indexOfWholeWordIgnoreCase (const tchar* const word) const throw()
- {
- if (word != 0 && *word != 0)
- {
- const int wordLen = CharacterFunctions::length (word);
- const int end = length() - wordLen;
- const tchar* t = text->text;
-
- for (int i = 0; i <= end; ++i)
- {
- if (CharacterFunctions::compareIgnoreCase (t, word, wordLen) == 0
- && (i == 0 || ! CharacterFunctions::isLetterOrDigit (* (t - 1)))
- && ! CharacterFunctions::isLetterOrDigit (t [wordLen]))
- {
- return i;
- }
-
- ++t;
- }
- }
-
- return -1;
- }
-
- bool String::containsWholeWord (const tchar* const wordToLookFor) const throw()
- {
- return indexOfWholeWord (wordToLookFor) >= 0;
- }
-
- bool String::containsWholeWordIgnoreCase (const tchar* const wordToLookFor) const throw()
- {
- return indexOfWholeWordIgnoreCase (wordToLookFor) >= 0;
- }
-
- //==============================================================================
- static int indexOfMatch (const tchar* const wildcard,
- const tchar* const test,
- const bool ignoreCase) throw()
- {
- int start = 0;
-
- while (test [start] != 0)
- {
- int i = 0;
-
- for (;;)
- {
- const tchar wc = wildcard [i];
- const tchar c = test [i + start];
-
- if (wc == c
- || (ignoreCase && CharacterFunctions::toLowerCase (wc) == CharacterFunctions::toLowerCase (c))
- || (wc == T('?') && c != 0))
- {
- if (wc == 0)
- return start;
-
- ++i;
- }
- else
- {
- if (wc == T('*') && (wildcard [i + 1] == 0
- || indexOfMatch (wildcard + i + 1,
- test + start + i,
- ignoreCase) >= 0))
- {
- return start;
- }
-
- break;
- }
- }
-
- ++start;
- }
-
- return -1;
- }
-
- bool String::matchesWildcard (const tchar* wildcard, const bool ignoreCase) const throw()
- {
- int i = 0;
-
- for (;;)
- {
- const tchar wc = wildcard [i];
- const tchar c = text->text [i];
-
- if (wc == c
- || (ignoreCase && CharacterFunctions::toLowerCase (wc) == CharacterFunctions::toLowerCase (c))
- || (wc == T('?') && c != 0))
- {
- if (wc == 0)
- return true;
-
- ++i;
- }
- else
- {
- return wc == T('*') && (wildcard [i + 1] == 0
- || indexOfMatch (wildcard + i + 1,
- text->text + i,
- ignoreCase) >= 0);
- }
- }
- }
-
- //==============================================================================
- void String::printf (const tchar* const pf, ...) throw()
- {
- va_list list;
- va_start (list, pf);
-
- vprintf (pf, list);
- }
-
- const String String::formatted (const tchar* const pf, ...) throw()
- {
- va_list list;
- va_start (list, pf);
-
- String result;
- result.vprintf (pf, list);
- return result;
- }
-
- //==============================================================================
- void String::vprintf (const tchar* const pf, va_list& args) throw()
- {
- tchar stackBuf [256];
- unsigned int bufSize = 256;
- tchar* buf = stackBuf;
-
- deleteInternal();
-
- do
- {
- #if JUCE_LINUX && JUCE_64BIT
- va_list tempArgs;
- va_copy (tempArgs, args);
- const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, tempArgs);
- va_end (tempArgs);
- #else
- const int num = CharacterFunctions::vprintf (buf, bufSize - 1, pf, args);
- #endif
-
- if (num > 0)
- {
- createInternal (num);
- memcpy (text->text, buf, (num + 1) * sizeof (tchar));
- break;
- }
- else if (num == 0)
- {
- text = &emptyString;
- emptyString.refCount = safeEmptyStringRefCount;
- break;
- }
-
- if (buf != stackBuf)
- juce_free (buf);
-
- bufSize += 256;
- buf = (tchar*) juce_malloc (bufSize * sizeof (tchar));
- }
- while (bufSize < 65536); // this is a sanity check to avoid situations where vprintf repeatedly
- // returns -1 because of an error rather than because it needs more space.
-
- if (buf != stackBuf)
- juce_free (buf);
- }
-
- //==============================================================================
- const String String::repeatedString (const tchar* const stringToRepeat,
- int numberOfTimesToRepeat) throw()
- {
- const int len = CharacterFunctions::length (stringToRepeat);
- String result ((int) (len * numberOfTimesToRepeat + 1), (int) 0);
-
- tchar* n = result.text->text;
- n[0] = 0;
-
- while (--numberOfTimesToRepeat >= 0)
- {
- CharacterFunctions::append (n, stringToRepeat);
- n += len;
- }
-
- return result;
- }
-
- //==============================================================================
- const String String::replaceSection (int index,
- int numCharsToReplace,
- const tchar* const stringToInsert) const throw()
- {
- if (index < 0)
- {
- // a negative index to replace from?
- jassertfalse
- index = 0;
- }
-
- if (numCharsToReplace < 0)
- {
- // replacing a negative number of characters?
- numCharsToReplace = 0;
- jassertfalse;
- }
-
- const int len = length();
-
- if (index + numCharsToReplace > len)
- {
- if (index > len)
- {
- // replacing beyond the end of the string?
- index = len;
- jassertfalse
- }
-
- numCharsToReplace = len - index;
- }
-
- const int newStringLen = (stringToInsert != 0) ? CharacterFunctions::length (stringToInsert) : 0;
- const int newTotalLen = len + newStringLen - numCharsToReplace;
-
- if (newTotalLen <= 0)
- return String::empty;
-
- String result (newTotalLen, (int) 0);
-
- memcpy (result.text->text,
- text->text,
- index * sizeof (tchar));
-
- if (newStringLen > 0)
- memcpy (result.text->text + index,
- stringToInsert,
- newStringLen * sizeof (tchar));
-
- const int endStringLen = newTotalLen - (index + newStringLen);
-
- if (endStringLen > 0)
- memcpy (result.text->text + (index + newStringLen),
- text->text + (index + numCharsToReplace),
- endStringLen * sizeof (tchar));
-
- result.text->text [newTotalLen] = 0;
-
- return result;
- }
-
- const String String::replace (const tchar* const stringToReplace,
- const tchar* const stringToInsert,
- const bool ignoreCase) const throw()
- {
- const int stringToReplaceLen = CharacterFunctions::length (stringToReplace);
- const int stringToInsertLen = CharacterFunctions::length (stringToInsert);
-
- int i = 0;
- String result (*this);
-
- while ((i = (ignoreCase ? result.indexOfIgnoreCase (i, stringToReplace)
- : result.indexOf (i, stringToReplace))) >= 0)
- {
- result = result.replaceSection (i, stringToReplaceLen, stringToInsert);
- i += stringToInsertLen;
- }
-
- return result;
- }
-
- const String String::replaceCharacter (const tchar charToReplace,
- const tchar charToInsert) const throw()
- {
- const int index = indexOfChar (charToReplace);
-
- if (index < 0)
- return *this;
-
- String result (*this);
- result.dupeInternalIfMultiplyReferenced();
-
- tchar* t = result.text->text + index;
-
- while (*t != 0)
- {
- if (*t == charToReplace)
- *t = charToInsert;
-
- ++t;
- }
-
- return result;
- }
-
- const String String::replaceCharacters (const String& charactersToReplace,
- const tchar* const charactersToInsertInstead) const throw()
- {
- String result (*this);
- result.dupeInternalIfMultiplyReferenced();
-
- tchar* t = result.text->text;
- const int len2 = CharacterFunctions::length (charactersToInsertInstead);
-
- // the two strings passed in are supposed to be the same length!
- jassert (len2 == charactersToReplace.length());
-
- while (*t != 0)
- {
- const int index = charactersToReplace.indexOfChar (*t);
-
- if (((unsigned int) index) < (unsigned int) len2)
- *t = charactersToInsertInstead [index];
-
- ++t;
- }
-
- return result;
- }
-
- //==============================================================================
- bool String::startsWith (const tchar* const other) const throw()
- {
- return other != 0
- && CharacterFunctions::compare (text->text, other, CharacterFunctions::length (other)) == 0;
- }
-
- bool String::startsWithIgnoreCase (const tchar* const other) const throw()
- {
- return other != 0
- && CharacterFunctions::compareIgnoreCase (text->text, other, CharacterFunctions::length (other)) == 0;
- }
-
- bool String::startsWithChar (const tchar character) const throw()
- {
- jassert (character != 0); // strings can't contain a null character!
-
- return text->text[0] == character;
- }
-
- bool String::endsWithChar (const tchar character) const throw()
- {
- jassert (character != 0); // strings can't contain a null character!
-
- return text->text[0] != 0
- && text->text [length() - 1] == character;
- }
-
- bool String::endsWith (const tchar* const other) const throw()
- {
- if (other == 0)
- return false;
-
- const int thisLen = length();
- const int otherLen = CharacterFunctions::length (other);
-
- return thisLen >= otherLen
- && CharacterFunctions::compare (text->text + thisLen - otherLen, other) == 0;
- }
-
- bool String::endsWithIgnoreCase (const tchar* const other) const throw()
- {
- if (other == 0)
- return false;
-
- const int thisLen = length();
- const int otherLen = CharacterFunctions::length (other);
-
- return thisLen >= otherLen
- && CharacterFunctions::compareIgnoreCase (text->text + thisLen - otherLen, other) == 0;
- }
-
- //==============================================================================
- const String String::toUpperCase() const throw()
- {
- String result (*this);
- result.dupeInternalIfMultiplyReferenced();
- CharacterFunctions::toUpperCase (result.text->text);
- return result;
- }
-
- const String String::toLowerCase() const throw()
- {
- String result (*this);
- result.dupeInternalIfMultiplyReferenced();
- CharacterFunctions::toLowerCase (result.text->text);
- return result;
- }
-
- //==============================================================================
- tchar& String::operator[] (const int index) throw()
- {
- jassert (((unsigned int) index) <= (unsigned int) length());
-
- dupeInternalIfMultiplyReferenced();
-
- return text->text [index];
- }
-
- tchar String::getLastCharacter() const throw()
- {
- return (isEmpty()) ? ((tchar) 0)
- : text->text [CharacterFunctions::length (text->text) - 1];
- }
-
- const String String::substring (int start, int end) const throw()
- {
- if (start < 0)
- start = 0;
- else if (end <= start)
- return empty;
-
- int len = 0;
- const tchar* const t = text->text;
-
- while (len <= end && t [len] != 0)
- ++len;
-
- if (end >= len)
- {
- if (start == 0)
- return *this;
-
- end = len;
- }
-
- return String (text->text + start,
- end - start);
- }
-
- const String String::substring (const int start) const throw()
- {
- if (start <= 0)
- return *this;
-
- const int len = CharacterFunctions::length (text->text);
-
- if (start >= len)
- return empty;
- else
- return String (text->text + start,
- len - start);
- }
-
- const String String::dropLastCharacters (const int numberToDrop) const throw()
- {
- return String (text->text,
- jmax (0, CharacterFunctions::length (text->text) - numberToDrop));
- }
-
- const String String::getLastCharacters (const int numCharacters) const throw()
- {
- return String (text->text + jmax (0, CharacterFunctions::length (text->text) - jmax (0, numCharacters)));
- }
-
- const String String::fromFirstOccurrenceOf (const tchar* const sub,
- const bool includeSubString,
- const bool ignoreCase) const throw()
- {
- const int i = ignoreCase ? indexOfIgnoreCase (sub)
- : indexOf (sub);
-
- if (i < 0)
- return empty;
- else
- return substring (includeSubString ? i : i + CharacterFunctions::length (sub));
- }
-
-
- const String String::fromLastOccurrenceOf (const tchar* const sub,
- const bool includeSubString,
- const bool ignoreCase) const throw()
- {
- const int i = ignoreCase ? lastIndexOfIgnoreCase (sub)
- : lastIndexOf (sub);
-
- if (i < 0)
- return *this;
- else
- return substring (includeSubString ? i : i + CharacterFunctions::length (sub));
- }
-
- const String String::upToFirstOccurrenceOf (const tchar* const sub,
- const bool includeSubString,
- const bool ignoreCase) const throw()
- {
- const int i = ignoreCase ? indexOfIgnoreCase (sub)
- : indexOf (sub);
-
- if (i < 0)
- return *this;
- else
- return substring (0, includeSubString ? i + CharacterFunctions::length (sub) : i);
- }
-
- const String String::upToLastOccurrenceOf (const tchar* const sub,
- const bool includeSubString,
- const bool ignoreCase) const throw()
- {
- const int i = ignoreCase ? lastIndexOfIgnoreCase (sub)
- : lastIndexOf (sub);
- if (i < 0)
- return *this;
-
- return substring (0, includeSubString ? i + CharacterFunctions::length (sub) : i);
- }
-
- bool String::isQuotedString() const throw()
- {
- const String trimmed (trimStart());
-
- return trimmed[0] == T('"')
- || trimmed[0] == T('\'');
- }
-
- const String String::unquoted() const throw()
- {
- String s (*this);
-
- if (s[0] == T('"') || s[0] == T('\''))
- s = s.substring (1);
-
- const int lastCharIndex = s.length() - 1;
-
- if (lastCharIndex >= 0
- && (s [lastCharIndex] == T('"') || s[lastCharIndex] == T('\'')))
- s [lastCharIndex] = 0;
-
- return s;
- }
-
- const String String::quoted (const tchar quoteCharacter) const throw()
- {
- if (isEmpty())
- return charToString (quoteCharacter) + quoteCharacter;
-
- String t (*this);
-
- if (! t.startsWithChar (quoteCharacter))
- t = charToString (quoteCharacter) + t;
-
- if (! t.endsWithChar (quoteCharacter))
- t += quoteCharacter;
-
- return t;
- }
-
- //==============================================================================
- const String String::trim() const throw()
- {
- if (isEmpty())
- return empty;
-
- int start = 0;
-
- while (CharacterFunctions::isWhitespace (text->text [start]))
- ++start;
-
- const int len = CharacterFunctions::length (text->text);
- int end = len - 1;
-
- while ((end >= start) && CharacterFunctions::isWhitespace (text->text [end]))
- --end;
-
- ++end;
-
- if (end <= start)
- return empty;
- else if (start > 0 || end < len)
- return String (text->text + start, end - start);
- else
- return *this;
- }
-
- const String String::trimStart() const throw()
- {
- if (isEmpty())
- return empty;
-
- const tchar* t = text->text;
-
- while (CharacterFunctions::isWhitespace (*t))
- ++t;
-
- if (t == text->text)
- return *this;
- else
- return String (t);
- }
-
- const String String::trimEnd() const throw()
- {
- if (isEmpty())
- return empty;
-
- const tchar* endT = text->text + (CharacterFunctions::length (text->text) - 1);
-
- while ((endT >= text->text) && CharacterFunctions::isWhitespace (*endT))
- --endT;
-
- return String (text->text, (int) (++endT - text->text));
- }
-
- const String String::trimCharactersAtStart (const tchar* charactersToTrim) const throw()
- {
- jassert (charactersToTrim != 0);
-
- if (isEmpty())
- return empty;
-
- const tchar* t = text->text;
-
- while (CharacterFunctions::indexOfCharFast (charactersToTrim, *t) >= 0)
- ++t;
-
- if (t == text->text)
- return *this;
- else
- return String (t);
- }
-
- const String String::trimCharactersAtEnd (const tchar* charactersToTrim) const throw()
- {
- jassert (charactersToTrim != 0);
-
- if (isEmpty())
- return empty;
-
- const tchar* endT = text->text + (CharacterFunctions::length (text->text) - 1);
-
- while ((endT >= text->text) && CharacterFunctions::indexOfCharFast (charactersToTrim, *endT) >= 0)
- --endT;
-
- return String (text->text, (int) (++endT - text->text));
- }
-
- //==============================================================================
- const String String::retainCharacters (const tchar* const charactersToRetain) const throw()
- {
- jassert (charactersToRetain != 0);
-
- if (isEmpty())
- return empty;
-
- String result (text->allocatedNumChars, (int) 0);
- tchar* dst = result.text->text;
- const tchar* src = text->text;
-
- while (*src != 0)
- {
- if (CharacterFunctions::indexOfCharFast (charactersToRetain, *src) >= 0)
- *dst++ = *src;
-
- ++src;
- }
-
- *dst = 0;
- return result;
- }
-
- const String String::removeCharacters (const tchar* const charactersToRemove) const throw()
- {
- jassert (charactersToRemove != 0);
-
- if (isEmpty())
- return empty;
-
- String result (text->allocatedNumChars, (int) 0);
- tchar* dst = result.text->text;
- const tchar* src = text->text;
-
- while (*src != 0)
- {
- if (CharacterFunctions::indexOfCharFast (charactersToRemove, *src) < 0)
- *dst++ = *src;
-
- ++src;
- }
-
- *dst = 0;
- return result;
- }
-
- const String String::initialSectionContainingOnly (const tchar* const permittedCharacters) const throw()
- {
- return substring (0, CharacterFunctions::getIntialSectionContainingOnly (text->text, permittedCharacters));
- }
-
- const String String::initialSectionNotContaining (const tchar* const charactersToStopAt) const throw()
- {
- jassert (charactersToStopAt != 0);
-
- const tchar* const t = text->text;
- int i = 0;
-
- while (t[i] != 0)
- {
- if (CharacterFunctions::indexOfCharFast (charactersToStopAt, t[i]) >= 0)
- return String (text->text, i);
-
- ++i;
- }
-
- return empty;
- }
-
- bool String::containsOnly (const tchar* const chars) const throw()
- {
- jassert (chars != 0);
-
- const tchar* t = text->text;
-
- while (*t != 0)
- if (CharacterFunctions::indexOfCharFast (chars, *t++) < 0)
- return false;
-
- return true;
- }
-
- bool String::containsAnyOf (const tchar* const chars) const throw()
- {
- jassert (chars != 0);
-
- const tchar* t = text->text;
-
- while (*t != 0)
- if (CharacterFunctions::indexOfCharFast (chars, *t++) >= 0)
- return true;
-
- return false;
- }
-
- bool String::containsNonWhitespaceChars() const throw()
- {
- const tchar* t = text->text;
-
- while (*t != 0)
- if (! CharacterFunctions::isWhitespace (*t++))
- return true;
-
- return false;
- }
-
-
- //==============================================================================
- int String::getIntValue() const throw()
- {
- return CharacterFunctions::getIntValue (text->text);
- }
-
- int String::getTrailingIntValue() const throw()
- {
- int n = 0;
- int mult = 1;
- const tchar* t = text->text + length();
-
- while (--t >= text->text)
- {
- const tchar c = *t;
-
- if (! CharacterFunctions::isDigit (c))
- {
- if (c == T('-'))
- n = -n;
-
- break;
- }
-
- n += mult * (c - T('0'));
- mult *= 10;
- }
-
- return n;
- }
-
- int64 String::getLargeIntValue() const throw()
- {
- return CharacterFunctions::getInt64Value (text->text);
- }
-
- float String::getFloatValue() const throw()
- {
- return (float) CharacterFunctions::getDoubleValue (text->text);
- }
-
- double String::getDoubleValue() const throw()
- {
- return CharacterFunctions::getDoubleValue (text->text);
- }
-
- static const tchar* const hexDigits = T("0123456789abcdef");
-
- const String String::toHexString (const int number) throw()
- {
- tchar buffer[32];
- tchar* const end = buffer + 32;
- tchar* t = end;
- *--t = 0;
- unsigned int v = (unsigned int) number;
-
- do
- {
- *--t = hexDigits [v & 15];
- v >>= 4;
-
- } while (v != 0);
-
- return String (t, (int) (((char*) end) - (char*) t) - 1);
- }
-
- const String String::toHexString (const int64 number) throw()
- {
- tchar buffer[32];
- tchar* const end = buffer + 32;
- tchar* t = end;
- *--t = 0;
- uint64 v = (uint64) number;
-
- do
- {
- *--t = hexDigits [(int) (v & 15)];
- v >>= 4;
-
- } while (v != 0);
-
- return String (t, (int) (((char*) end) - (char*) t));
- }
-
- const String String::toHexString (const short number) throw()
- {
- return toHexString ((int) (unsigned short) number);
- }
-
- const String String::toHexString (const unsigned char* data,
- const int size,
- const int groupSize) throw()
- {
- if (size <= 0)
- return empty;
-
- int numChars = (size * 2) + 2;
- if (groupSize > 0)
- numChars += size / groupSize;
-
- String s (numChars, (int) 0);
-
- tchar* d = s.text->text;
-
- for (int i = 0; i < size; ++i)
- {
- *d++ = hexDigits [(*data) >> 4];
- *d++ = hexDigits [(*data) & 0xf];
- ++data;
-
- if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1))
- *d++ = T(' ');
- }
-
- *d = 0;
- return s;
- }
-
- int String::getHexValue32() const throw()
- {
- int result = 0;
- const tchar* c = text->text;
-
- for (;;)
- {
- const int hexValue = CharacterFunctions::getHexDigitValue (*c);
-
- if (hexValue >= 0)
- result = (result << 4) | hexValue;
- else if (*c == 0)
- break;
-
- ++c;
- }
-
- return result;
- }
-
- int64 String::getHexValue64() const throw()
- {
- int64 result = 0;
- const tchar* c = text->text;
-
- for (;;)
- {
- const int hexValue = CharacterFunctions::getHexDigitValue (*c);
-
- if (hexValue >= 0)
- result = (result << 4) | hexValue;
- else if (*c == 0)
- break;
-
- ++c;
- }
-
- return result;
- }
-
- //==============================================================================
- const String String::createStringFromData (const void* const data_,
- const int size) throw()
- {
- const char* const data = (const char*) data_;
-
- if (size <= 0 || data == 0)
- {
- return empty;
- }
- else if (size < 2)
- {
- return charToString (data[0]);
- }
- else if ((data[0] == (char)-2 && data[1] == (char)-1)
- || (data[0] == (char)-1 && data[1] == (char)-2))
- {
- // assume it's 16-bit unicode
- const bool bigEndian = (data[0] == (char)-2);
- const int numChars = size / 2 - 1;
-
- String result;
- result.preallocateStorage (numChars + 2);
-
- const uint16* const src = (const uint16*) (data + 2);
- tchar* const dst = const_cast <tchar*> ((const tchar*) result);
-
- if (bigEndian)
- {
- for (int i = 0; i < numChars; ++i)
- dst[i] = (tchar) swapIfLittleEndian (src[i]);
- }
- else
- {
- for (int i = 0; i < numChars; ++i)
- dst[i] = (tchar) swapIfBigEndian (src[i]);
- }
-
- dst [numChars] = 0;
- return result;
- }
- else
- {
- return String::fromUTF8 ((const uint8*) data, size);
- }
- }
-
- //==============================================================================
- const char* String::toUTF8() const throw()
- {
- if (isEmpty())
- {
- return (const char*) emptyCharString;
- }
- else
- {
- String* const mutableThis = const_cast <String*> (this);
-
- mutableThis->dupeInternalIfMultiplyReferenced();
-
- const int currentLen = CharacterFunctions::length (text->text) + 1;
- const int utf8BytesNeeded = copyToUTF8 (0);
-
- mutableThis->text = (InternalRefCountedStringHolder*)
- juce_realloc (text, sizeof (InternalRefCountedStringHolder)
- + (currentLen * sizeof (juce_wchar) + utf8BytesNeeded));
-
- char* const otherCopy = (char*) (text->text + currentLen);
- copyToUTF8 ((uint8*) otherCopy);
-
- return otherCopy;
- }
- }
-
- int String::copyToUTF8 (uint8* const buffer, const int maxBufferSizeBytes) const throw()
- {
- jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied!
-
- #if JUCE_STRINGS_ARE_UNICODE
- int num = 0, index = 0;
-
- for (;;)
- {
- const uint32 c = (uint32) text->text [index++];
-
- if (c >= 0x80)
- {
- int numExtraBytes = 1;
-
- if (c >= 0x800)
- {
- ++numExtraBytes;
-
- if (c >= 0x10000)
- {
- ++numExtraBytes;
-
- if (c >= 0x200000)
- {
- ++numExtraBytes;
-
- if (c >= 0x4000000)
- ++numExtraBytes;
- }
- }
- }
-
- if (buffer != 0)
- {
- if (num + numExtraBytes >= maxBufferSizeBytes)
- {
- buffer [num++] = 0;
- break;
- }
- else
- {
- buffer [num++] = (uint8) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6)));
-
- while (--numExtraBytes >= 0)
- buffer [num++] = (uint8) (0x80 | (0x3f & (c >> (numExtraBytes * 6))));
- }
- }
- else
- {
- num += numExtraBytes + 1;
- }
- }
- else
- {
- if (buffer != 0)
- {
- if (num + 1 >= maxBufferSizeBytes)
- {
- buffer [num++] = 0;
- break;
- }
-
- buffer [num] = (uint8) c;
- }
-
- ++num;
- }
-
- if (c == 0)
- break;
- }
-
- return num;
-
- #else
- const int numBytes = jmin (maxBufferSizeBytes, length() + 1);
-
- if (buffer != 0)
- copyToBuffer ((char*) buffer, maxBufferSizeBytes);
-
- return numBytes;
- #endif
- }
-
- const String String::fromUTF8 (const uint8* const buffer, int bufferSizeBytes) throw()
- {
- if (buffer == 0)
- return empty;
-
- if (bufferSizeBytes < 0)
- bufferSizeBytes = INT_MAX;
-
- int numBytes;
- for (numBytes = 0; numBytes < bufferSizeBytes; ++numBytes)
- if (buffer [numBytes] == 0)
- break;
-
- String result (numBytes + 1, 0);
- tchar* dest = result.text->text;
-
- int i = 0;
- while (i < numBytes)
- {
- const uint8 c = buffer [i++];
-
- if ((c & 0x80) != 0)
- {
- int mask = 0x7f;
- int bit = 0x40;
- int numExtraValues = 0;
-
- while (bit != 0 && (c & bit) != 0)
- {
- bit >>= 1;
- mask >>= 1;
- ++numExtraValues;
- }
-
- int n = (c & mask);
-
- while (--numExtraValues >= 0 && i < bufferSizeBytes)
- {
- const uint8 c = buffer[i];
-
- if ((c & 0xc0) != 0x80)
- break;
-
- n <<= 6;
- n |= (c & 0x3f);
- ++i;
- }
-
- *dest++ = (tchar) n;
- }
- else
- {
- *dest++ = (tchar) c;
- }
- }
-
- *dest = 0;
- return result;
- }
-
-
- END_JUCE_NAMESPACE
|