- added JUCE library code

git-svn-id: http://moon:8086/svn/software/trunk/projects/FsTrack@357 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2018-06-12 16:53:56 +00:00
parent fd05a8501a
commit 88f2f0e9aa
755 changed files with 269502 additions and 0 deletions
@@ -0,0 +1,387 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_CHARPOINTER_ASCII_H_INCLUDED
#define JUCE_CHARPOINTER_ASCII_H_INCLUDED
//==============================================================================
/**
Wraps a pointer to a null-terminated ASCII character string, and provides
various methods to operate on the data.
A valid ASCII string is assumed to not contain any characters above 127.
@see CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
*/
class CharPointer_ASCII
{
public:
typedef char CharType;
inline explicit CharPointer_ASCII (const CharType* const rawPointer) noexcept
: data (const_cast <CharType*> (rawPointer))
{
}
inline CharPointer_ASCII (const CharPointer_ASCII& other) noexcept
: data (other.data)
{
}
inline CharPointer_ASCII operator= (const CharPointer_ASCII other) noexcept
{
data = other.data;
return *this;
}
inline CharPointer_ASCII operator= (const CharType* text) noexcept
{
data = const_cast <CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
inline bool operator== (CharPointer_ASCII other) const noexcept { return data == other.data; }
inline bool operator!= (CharPointer_ASCII other) const noexcept { return data != other.data; }
inline bool operator<= (CharPointer_ASCII other) const noexcept { return data <= other.data; }
inline bool operator< (CharPointer_ASCII other) const noexcept { return data < other.data; }
inline bool operator>= (CharPointer_ASCII other) const noexcept { return data >= other.data; }
inline bool operator> (CharPointer_ASCII other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
inline CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
inline operator const CharType*() const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
inline bool isEmpty() const noexcept { return *data == 0; }
/** Returns the unicode character that this pointer is pointing to. */
inline juce_wchar operator*() const noexcept { return (juce_wchar) (uint8) *data; }
/** Moves this pointer along to the next character in the string. */
inline CharPointer_ASCII operator++() noexcept
{
++data;
return *this;
}
/** Moves this pointer to the previous character in the string. */
inline CharPointer_ASCII operator--() noexcept
{
--data;
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
inline juce_wchar getAndAdvance() noexcept { return (juce_wchar) (uint8) *data++; }
/** Moves this pointer along to the next character in the string. */
CharPointer_ASCII operator++ (int) noexcept
{
CharPointer_ASCII temp (*this);
++data;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
inline void operator+= (const int numToSkip) noexcept
{
data += numToSkip;
}
inline void operator-= (const int numToSkip) noexcept
{
data -= numToSkip;
}
/** Returns the character at a given character index from the start of the string. */
inline juce_wchar operator[] (const int characterIndex) const noexcept
{
return (juce_wchar) (unsigned char) data [characterIndex];
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_ASCII operator+ (const int numToSkip) const noexcept
{
return CharPointer_ASCII (data + numToSkip);
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_ASCII operator- (const int numToSkip) const noexcept
{
return CharPointer_ASCII (data - numToSkip);
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
inline void write (const juce_wchar charToWrite) noexcept
{
*data++ = (char) charToWrite;
}
inline void replaceChar (const juce_wchar newChar) noexcept
{
*data = (char) newChar;
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
inline void writeNull() const noexcept
{
*data = 0;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
return (size_t) strlen (data);
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo (const CharPointer_ASCII end) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
return length() + 1;
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static inline size_t getBytesRequiredFor (const juce_wchar) noexcept
{
return 1;
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor (const CharPointer text) noexcept
{
return text.length();
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_ASCII findTerminatingNull() const noexcept
{
return CharPointer_ASCII (data + length());
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll (const CharPointer src) noexcept
{
CharacterFunctions::copyAll (*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
void writeAll (const CharPointer_ASCII src) noexcept
{
strcpy (data, src.data);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare (const CharPointer other) const noexcept
{
return CharacterFunctions::compare (*this, other);
}
/** Compares this string with another one. */
int compare (const CharPointer_ASCII other) const noexcept
{
return strcmp (data, other.data);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo (*this, other, maxChars);
}
/** Compares this string with another one, up to a specified number of characters. */
int compareUpTo (const CharPointer_ASCII other, const int maxChars) const noexcept
{
return strncmp (data, other.data, (size_t) maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase (const CharPointer other) const
{
return CharacterFunctions::compareIgnoreCase (*this, other);
}
int compareIgnoreCase (const CharPointer_ASCII other) const
{
#if JUCE_WINDOWS
return stricmp (data, other.data);
#else
return strcasecmp (data, other.data);
#endif
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
}
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf (const CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf (*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind) const noexcept
{
int i = 0;
while (data[i] != 0)
{
if (data[i] == (char) charToFind)
return i;
++i;
}
return -1;
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
: CharacterFunctions::indexOfChar (*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const { return CharacterFunctions::isWhitespace (*data) != 0; }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const { return CharacterFunctions::isDigit (*data) != 0; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const { return CharacterFunctions::isLetter (*data) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const { return CharacterFunctions::isUpperCase ((juce_wchar) (uint8) *data) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const { return CharacterFunctions::isLowerCase ((juce_wchar) (uint8) *data) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase ((juce_wchar) (uint8) *data); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase ((juce_wchar) (uint8) *data); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept { return atoi (data); }
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept
{
#if JUCE_LINUX || JUCE_ANDROID
return atoll (data);
#elif JUCE_WINDOWS
return _atoi64 (data);
#else
return CharacterFunctions::getIntValue <int64, CharPointer_ASCII> (*this);
#endif
}
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_ASCII findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
return ((unsigned int) character) < (unsigned int) 128;
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
{
while (--maxBytesToRead >= 0)
{
if (((signed char) *dataToTest) <= 0)
return *dataToTest == 0;
++dataToTest;
}
return true;
}
private:
CharType* data;
};
#endif // JUCE_CHARPOINTER_ASCII_H_INCLUDED
@@ -0,0 +1,525 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_CHARPOINTER_UTF16_H_INCLUDED
#define JUCE_CHARPOINTER_UTF16_H_INCLUDED
//==============================================================================
/**
Wraps a pointer to a null-terminated UTF-16 character string, and provides
various methods to operate on the data.
@see CharPointer_UTF8, CharPointer_UTF32
*/
class CharPointer_UTF16
{
public:
#if JUCE_NATIVE_WCHAR_IS_UTF16
typedef wchar_t CharType;
#else
typedef int16 CharType;
#endif
inline explicit CharPointer_UTF16 (const CharType* const rawPointer) noexcept
: data (const_cast <CharType*> (rawPointer))
{
}
inline CharPointer_UTF16 (const CharPointer_UTF16& other) noexcept
: data (other.data)
{
}
inline CharPointer_UTF16 operator= (CharPointer_UTF16 other) noexcept
{
data = other.data;
return *this;
}
inline CharPointer_UTF16 operator= (const CharType* text) noexcept
{
data = const_cast <CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
inline bool operator== (CharPointer_UTF16 other) const noexcept { return data == other.data; }
inline bool operator!= (CharPointer_UTF16 other) const noexcept { return data != other.data; }
inline bool operator<= (CharPointer_UTF16 other) const noexcept { return data <= other.data; }
inline bool operator< (CharPointer_UTF16 other) const noexcept { return data < other.data; }
inline bool operator>= (CharPointer_UTF16 other) const noexcept { return data >= other.data; }
inline bool operator> (CharPointer_UTF16 other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
inline CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
inline operator const CharType*() const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
inline bool isEmpty() const noexcept { return *data == 0; }
/** Returns the unicode character that this pointer is pointing to. */
juce_wchar operator*() const noexcept
{
uint32 n = (uint32) (uint16) *data;
if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) data[1]) >= 0xdc00)
n = 0x10000 + (((n - 0xd800) << 10) | (((uint32) (uint16) data[1]) - 0xdc00));
return (juce_wchar) n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF16 operator++() noexcept
{
const juce_wchar n = *data++;
if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00)
++data;
return *this;
}
/** Moves this pointer back to the previous character in the string. */
CharPointer_UTF16 operator--() noexcept
{
const juce_wchar n = *--data;
if (n >= 0xdc00 && n <= 0xdfff)
--data;
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
juce_wchar getAndAdvance() noexcept
{
uint32 n = (uint32) (uint16) *data++;
if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00)
n = 0x10000 + ((((n - 0xd800) << 10) | (((uint32) (uint16) *data++) - 0xdc00)));
return (juce_wchar) n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF16 operator++ (int) noexcept
{
CharPointer_UTF16 temp (*this);
++*this;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
void operator+= (int numToSkip) noexcept
{
if (numToSkip < 0)
{
while (++numToSkip <= 0)
--*this;
}
else
{
while (--numToSkip >= 0)
++*this;
}
}
/** Moves this pointer backwards by the specified number of characters. */
void operator-= (int numToSkip) noexcept
{
operator+= (-numToSkip);
}
/** Returns the character at a given character index from the start of the string. */
juce_wchar operator[] (const int characterIndex) const noexcept
{
CharPointer_UTF16 p (*this);
p += characterIndex;
return *p;
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_UTF16 operator+ (const int numToSkip) const noexcept
{
CharPointer_UTF16 p (*this);
p += numToSkip;
return p;
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF16 operator- (const int numToSkip) const noexcept
{
CharPointer_UTF16 p (*this);
p += -numToSkip;
return p;
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
void write (juce_wchar charToWrite) noexcept
{
if (charToWrite >= 0x10000)
{
charToWrite -= 0x10000;
*data++ = (CharType) (0xd800 + (charToWrite >> 10));
*data++ = (CharType) (0xdc00 + (charToWrite & 0x3ff));
}
else
{
*data++ = (CharType) charToWrite;
}
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
inline void writeNull() const noexcept
{
*data = 0;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
const CharType* d = data;
size_t count = 0;
for (;;)
{
const int n = *d++;
if (n >= 0xd800 && n <= 0xdfff)
{
if (*d++ == 0)
break;
}
else if (n == 0)
break;
++count;
}
return count;
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo (const CharPointer_UTF16 end) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
return sizeof (CharType) * (findNullIndex (data) + 1);
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static size_t getBytesRequiredFor (const juce_wchar charToWrite) noexcept
{
return (charToWrite >= 0x10000) ? (sizeof (CharType) * 2) : sizeof (CharType);
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor (CharPointer text) noexcept
{
size_t count = 0;
juce_wchar n;
while ((n = text.getAndAdvance()) != 0)
count += getBytesRequiredFor (n);
return count;
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_UTF16 findTerminatingNull() const noexcept
{
const CharType* t = data;
while (*t != 0)
++t;
return CharPointer_UTF16 (t);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll (const CharPointer src) noexcept
{
CharacterFunctions::copyAll (*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
void writeAll (const CharPointer_UTF16 src) noexcept
{
const CharType* s = src.data;
while ((*data = *s) != 0)
{
++data;
++s;
}
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare (const CharPointer other) const noexcept
{
return CharacterFunctions::compare (*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo (*this, other, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase (const CharPointer other) const noexcept
{
return CharacterFunctions::compareIgnoreCase (*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
}
#if JUCE_WINDOWS && ! DOXYGEN
int compareIgnoreCase (const CharPointer_UTF16 other) const noexcept
{
return _wcsicmp (data, other.data);
}
int compareIgnoreCaseUpTo (const CharPointer_UTF16 other, int maxChars) const noexcept
{
return _wcsnicmp (data, other.data, (size_t) maxChars);
}
int indexOf (const CharPointer_UTF16 stringToFind) const noexcept
{
const CharType* const t = wcsstr (data, stringToFind.getAddress());
return t == nullptr ? -1 : (int) (t - data);
}
#endif
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf (const CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf (*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind) const noexcept
{
return CharacterFunctions::indexOfChar (*this, charToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
: CharacterFunctions::indexOfChar (*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const noexcept { return CharacterFunctions::isWhitespace (operator*()) != 0; }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const noexcept { return CharacterFunctions::isDigit (operator*()) != 0; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const noexcept { return CharacterFunctions::isLetter (operator*()) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const noexcept { return CharacterFunctions::isLetterOrDigit (operator*()) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const noexcept { return CharacterFunctions::isUpperCase (operator*()) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const noexcept { return CharacterFunctions::isLowerCase (operator*()) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (operator*()); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (operator*()); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept
{
#if JUCE_WINDOWS
return _wtoi (data);
#else
return CharacterFunctions::getIntValue <int, CharPointer_UTF16> (*this);
#endif
}
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept
{
#if JUCE_WINDOWS
return _wtoi64 (data);
#else
return CharacterFunctions::getIntValue <int64, CharPointer_UTF16> (*this);
#endif
}
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF16 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
return ((unsigned int) character) < (unsigned int) 0x10ffff
&& (((unsigned int) character) < 0xd800 || ((unsigned int) character) > 0xdfff);
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
{
maxBytesToRead /= (int) sizeof (CharType);
while (--maxBytesToRead >= 0 && *dataToTest != 0)
{
const uint32 n = (uint32) (uint16) *dataToTest++;
if (n >= 0xd800)
{
if (n > 0x10ffff)
return false;
if (n <= 0xdfff)
{
if (n > 0xdc00)
return false;
const uint32 nextChar = (uint32) (uint16) *dataToTest++;
if (nextChar < 0xdc00 || nextChar > 0xdfff)
return false;
}
}
}
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF16 atomicSwap (const CharPointer_UTF16 newValue)
{
return CharPointer_UTF16 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
}
/** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */
enum
{
byteOrderMarkBE1 = 0xfe,
byteOrderMarkBE2 = 0xff,
byteOrderMarkLE1 = 0xff,
byteOrderMarkLE2 = 0xfe
};
/** Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (big endian).
The pointer must not be null, and must contain at least two valid bytes.
*/
static bool isByteOrderMarkBigEndian (const void* possibleByteOrder) noexcept
{
jassert (possibleByteOrder != nullptr);
const uint8* const c = static_cast<const uint8*> (possibleByteOrder);
return c[0] == (uint8) byteOrderMarkBE1
&& c[1] == (uint8) byteOrderMarkBE2;
}
/** Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (little endian).
The pointer must not be null, and must contain at least two valid bytes.
*/
static bool isByteOrderMarkLittleEndian (const void* possibleByteOrder) noexcept
{
jassert (possibleByteOrder != nullptr);
const uint8* const c = static_cast<const uint8*> (possibleByteOrder);
return c[0] == (uint8) byteOrderMarkLE1
&& c[1] == (uint8) byteOrderMarkLE2;
}
private:
CharType* data;
static unsigned int findNullIndex (const CharType* const t) noexcept
{
unsigned int n = 0;
while (t[n] != 0)
++n;
return n;
}
};
#endif // JUCE_CHARPOINTER_UTF16_H_INCLUDED
@@ -0,0 +1,378 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_CHARPOINTER_UTF32_H_INCLUDED
#define JUCE_CHARPOINTER_UTF32_H_INCLUDED
//==============================================================================
/**
Wraps a pointer to a null-terminated UTF-32 character string, and provides
various methods to operate on the data.
@see CharPointer_UTF8, CharPointer_UTF16
*/
class CharPointer_UTF32
{
public:
typedef juce_wchar CharType;
inline explicit CharPointer_UTF32 (const CharType* const rawPointer) noexcept
: data (const_cast <CharType*> (rawPointer))
{
}
inline CharPointer_UTF32 (const CharPointer_UTF32& other) noexcept
: data (other.data)
{
}
inline CharPointer_UTF32 operator= (CharPointer_UTF32 other) noexcept
{
data = other.data;
return *this;
}
inline CharPointer_UTF32 operator= (const CharType* text) noexcept
{
data = const_cast <CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
inline bool operator== (CharPointer_UTF32 other) const noexcept { return data == other.data; }
inline bool operator!= (CharPointer_UTF32 other) const noexcept { return data != other.data; }
inline bool operator<= (CharPointer_UTF32 other) const noexcept { return data <= other.data; }
inline bool operator< (CharPointer_UTF32 other) const noexcept { return data < other.data; }
inline bool operator>= (CharPointer_UTF32 other) const noexcept { return data >= other.data; }
inline bool operator> (CharPointer_UTF32 other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
inline CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
inline operator const CharType*() const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
inline bool isEmpty() const noexcept { return *data == 0; }
/** Returns the unicode character that this pointer is pointing to. */
inline juce_wchar operator*() const noexcept { return *data; }
/** Moves this pointer along to the next character in the string. */
inline CharPointer_UTF32 operator++() noexcept
{
++data;
return *this;
}
/** Moves this pointer to the previous character in the string. */
inline CharPointer_UTF32 operator--() noexcept
{
--data;
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
inline juce_wchar getAndAdvance() noexcept { return *data++; }
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF32 operator++ (int) noexcept
{
CharPointer_UTF32 temp (*this);
++data;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
inline void operator+= (const int numToSkip) noexcept
{
data += numToSkip;
}
inline void operator-= (const int numToSkip) noexcept
{
data -= numToSkip;
}
/** Returns the character at a given character index from the start of the string. */
inline juce_wchar& operator[] (const int characterIndex) const noexcept
{
return data [characterIndex];
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_UTF32 operator+ (const int numToSkip) const noexcept
{
return CharPointer_UTF32 (data + numToSkip);
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF32 operator- (const int numToSkip) const noexcept
{
return CharPointer_UTF32 (data - numToSkip);
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
inline void write (const juce_wchar charToWrite) noexcept
{
*data++ = charToWrite;
}
inline void replaceChar (const juce_wchar newChar) noexcept
{
*data = newChar;
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
inline void writeNull() const noexcept
{
*data = 0;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
#if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
return wcslen (data);
#else
size_t n = 0;
while (data[n] != 0)
++n;
return n;
#endif
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo (const CharPointer_UTF32 end) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
return sizeof (CharType) * (length() + 1);
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static inline size_t getBytesRequiredFor (const juce_wchar) noexcept
{
return sizeof (CharType);
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor (const CharPointer text) noexcept
{
return sizeof (CharType) * text.length();
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_UTF32 findTerminatingNull() const noexcept
{
return CharPointer_UTF32 (data + length());
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll (const CharPointer src) noexcept
{
CharacterFunctions::copyAll (*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
void writeAll (const CharPointer_UTF32 src) noexcept
{
const CharType* s = src.data;
while ((*data = *s) != 0)
{
++data;
++s;
}
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare (const CharPointer other) const noexcept
{
return CharacterFunctions::compare (*this, other);
}
#if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
/** Compares this string with another one. */
int compare (const CharPointer_UTF32 other) const noexcept
{
return wcscmp (data, other.data);
}
#endif
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo (*this, other, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase (const CharPointer other) const
{
return CharacterFunctions::compareIgnoreCase (*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
}
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf (const CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf (*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind) const noexcept
{
int i = 0;
while (data[i] != 0)
{
if (data[i] == charToFind)
return i;
++i;
}
return -1;
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
: CharacterFunctions::indexOfChar (*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const { return CharacterFunctions::isWhitespace (*data) != 0; }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const { return CharacterFunctions::isDigit (*data) != 0; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const { return CharacterFunctions::isLetter (*data) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const { return CharacterFunctions::isUpperCase (*data) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const { return CharacterFunctions::isLowerCase (*data) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (*data); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (*data); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept { return CharacterFunctions::getIntValue <int, CharPointer_UTF32> (*this); }
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept { return CharacterFunctions::getIntValue <int64, CharPointer_UTF32> (*this); }
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF32 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
return ((unsigned int) character) < (unsigned int) 0x10ffff;
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
{
maxBytesToRead /= (int) sizeof (CharType);
while (--maxBytesToRead >= 0 && *dataToTest != 0)
if (! canRepresent (*dataToTest++))
return false;
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF32 atomicSwap (const CharPointer_UTF32 newValue)
{
return CharPointer_UTF32 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
}
private:
CharType* data;
};
#endif // JUCE_CHARPOINTER_UTF32_H_INCLUDED
@@ -0,0 +1,572 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_CHARPOINTER_UTF8_H_INCLUDED
#define JUCE_CHARPOINTER_UTF8_H_INCLUDED
//==============================================================================
/**
Wraps a pointer to a null-terminated UTF-8 character string, and provides
various methods to operate on the data.
@see CharPointer_UTF16, CharPointer_UTF32
*/
class CharPointer_UTF8
{
public:
typedef char CharType;
inline explicit CharPointer_UTF8 (const CharType* const rawPointer) noexcept
: data (const_cast <CharType*> (rawPointer))
{
}
inline CharPointer_UTF8 (const CharPointer_UTF8& other) noexcept
: data (other.data)
{
}
inline CharPointer_UTF8 operator= (CharPointer_UTF8 other) noexcept
{
data = other.data;
return *this;
}
inline CharPointer_UTF8 operator= (const CharType* text) noexcept
{
data = const_cast <CharType*> (text);
return *this;
}
/** This is a pointer comparison, it doesn't compare the actual text. */
inline bool operator== (CharPointer_UTF8 other) const noexcept { return data == other.data; }
inline bool operator!= (CharPointer_UTF8 other) const noexcept { return data != other.data; }
inline bool operator<= (CharPointer_UTF8 other) const noexcept { return data <= other.data; }
inline bool operator< (CharPointer_UTF8 other) const noexcept { return data < other.data; }
inline bool operator>= (CharPointer_UTF8 other) const noexcept { return data >= other.data; }
inline bool operator> (CharPointer_UTF8 other) const noexcept { return data > other.data; }
/** Returns the address that this pointer is pointing to. */
inline CharType* getAddress() const noexcept { return data; }
/** Returns the address that this pointer is pointing to. */
inline operator const CharType*() const noexcept { return data; }
/** Returns true if this pointer is pointing to a null character. */
inline bool isEmpty() const noexcept { return *data == 0; }
/** Returns the unicode character that this pointer is pointing to. */
juce_wchar operator*() const noexcept
{
const signed char byte = (signed char) *data;
if (byte >= 0)
return (juce_wchar) (uint8) byte;
uint32 n = (uint32) (uint8) byte;
uint32 mask = 0x7f;
uint32 bit = 0x40;
size_t numExtraValues = 0;
while ((n & bit) != 0 && bit > 0x10)
{
mask >>= 1;
++numExtraValues;
bit >>= 1;
}
n &= mask;
for (size_t i = 1; i <= numExtraValues; ++i)
{
const uint8 nextByte = (uint8) data [i];
if ((nextByte & 0xc0) != 0x80)
break;
n <<= 6;
n |= (nextByte & 0x3f);
}
return (juce_wchar) n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF8& operator++() noexcept
{
jassert (*data != 0); // trying to advance past the end of the string?
const signed char n = (signed char) *data++;
if (n < 0)
{
juce_wchar bit = 0x40;
while ((n & bit) != 0 && bit > 0x8)
{
++data;
bit >>= 1;
}
}
return *this;
}
/** Moves this pointer back to the previous character in the string. */
CharPointer_UTF8 operator--() noexcept
{
int count = 0;
while ((*--data & 0xc0) == 0x80 && ++count < 4)
{}
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
juce_wchar getAndAdvance() noexcept
{
const signed char byte = (signed char) *data++;
if (byte >= 0)
return (juce_wchar) (uint8) byte;
uint32 n = (uint32) (uint8) byte;
uint32 mask = 0x7f;
uint32 bit = 0x40;
int numExtraValues = 0;
while ((n & bit) != 0 && bit > 0x8)
{
mask >>= 1;
++numExtraValues;
bit >>= 1;
}
n &= mask;
while (--numExtraValues >= 0)
{
const uint32 nextByte = (uint32) (uint8) *data;
if ((nextByte & 0xc0) != 0x80)
break;
++data;
n <<= 6;
n |= (nextByte & 0x3f);
}
return (juce_wchar) n;
}
/** Moves this pointer along to the next character in the string. */
CharPointer_UTF8 operator++ (int) noexcept
{
CharPointer_UTF8 temp (*this);
++*this;
return temp;
}
/** Moves this pointer forwards by the specified number of characters. */
void operator+= (int numToSkip) noexcept
{
if (numToSkip < 0)
{
while (++numToSkip <= 0)
--*this;
}
else
{
while (--numToSkip >= 0)
++*this;
}
}
/** Moves this pointer backwards by the specified number of characters. */
void operator-= (int numToSkip) noexcept
{
operator+= (-numToSkip);
}
/** Returns the character at a given character index from the start of the string. */
juce_wchar operator[] (int characterIndex) const noexcept
{
CharPointer_UTF8 p (*this);
p += characterIndex;
return *p;
}
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
CharPointer_UTF8 operator+ (int numToSkip) const noexcept
{
CharPointer_UTF8 p (*this);
p += numToSkip;
return p;
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF8 operator- (int numToSkip) const noexcept
{
CharPointer_UTF8 p (*this);
p += -numToSkip;
return p;
}
/** Returns the number of characters in this string. */
size_t length() const noexcept
{
const CharType* d = data;
size_t count = 0;
for (;;)
{
const uint32 n = (uint32) (uint8) *d++;
if ((n & 0x80) != 0)
{
while ((*d & 0xc0) == 0x80)
++d;
}
else if (n == 0)
break;
++count;
}
return count;
}
/** Returns the number of characters in this string, or the given value, whichever is lower. */
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
}
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
size_t lengthUpTo (const CharPointer_UTF8 end) const noexcept
{
return CharacterFunctions::lengthUpTo (*this, end);
}
/** Returns the number of bytes that are used to represent this string.
This includes the terminating null character.
*/
size_t sizeInBytes() const noexcept
{
jassert (data != nullptr);
return strlen (data) + 1;
}
/** Returns the number of bytes that would be needed to represent the given
unicode character in this encoding format.
*/
static size_t getBytesRequiredFor (const juce_wchar charToWrite) noexcept
{
size_t num = 1;
const uint32 c = (uint32) charToWrite;
if (c >= 0x80)
{
++num;
if (c >= 0x800)
{
++num;
if (c >= 0x10000)
++num;
}
}
return num;
}
/** Returns the number of bytes that would be needed to represent the given
string in this encoding format.
The value returned does NOT include the terminating null character.
*/
template <class CharPointer>
static size_t getBytesRequiredFor (CharPointer text) noexcept
{
size_t count = 0;
juce_wchar n;
while ((n = text.getAndAdvance()) != 0)
count += getBytesRequiredFor (n);
return count;
}
/** Returns a pointer to the null character that terminates this string. */
CharPointer_UTF8 findTerminatingNull() const noexcept
{
return CharPointer_UTF8 (data + strlen (data));
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
void write (const juce_wchar charToWrite) noexcept
{
const uint32 c = (uint32) charToWrite;
if (c >= 0x80)
{
int numExtraBytes = 1;
if (c >= 0x800)
{
++numExtraBytes;
if (c >= 0x10000)
++numExtraBytes;
}
*data++ = (CharType) ((uint32) (0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6)));
while (--numExtraBytes >= 0)
*data++ = (CharType) (0x80 | (0x3f & (c >> (numExtraBytes * 6))));
}
else
{
*data++ = (CharType) c;
}
}
/** Writes a null character to this string (leaving the pointer's position unchanged). */
inline void writeNull() const noexcept
{
*data = 0;
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
template <typename CharPointer>
void writeAll (const CharPointer src) noexcept
{
CharacterFunctions::copyAll (*this, src);
}
/** Copies a source string to this pointer, advancing this pointer as it goes. */
void writeAll (const CharPointer_UTF8 src) noexcept
{
const CharType* s = src.data;
while ((*data = *s) != 0)
{
++data;
++s;
}
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxDestBytes parameter specifies the maximum number of bytes that can be written
to the destination buffer before stopping.
*/
template <typename CharPointer>
size_t writeWithDestByteLimit (const CharPointer src, const size_t maxDestBytes) noexcept
{
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
}
/** Copies a source string to this pointer, advancing this pointer as it goes.
The maxChars parameter specifies the maximum number of characters that can be
written to the destination buffer before stopping (including the terminating null).
*/
template <typename CharPointer>
void writeWithCharLimit (const CharPointer src, const int maxChars) noexcept
{
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compare (const CharPointer other) const noexcept
{
return CharacterFunctions::compare (*this, other);
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareUpTo (*this, other, maxChars);
}
/** Compares this string with another one. */
template <typename CharPointer>
int compareIgnoreCase (const CharPointer other) const noexcept
{
return CharacterFunctions::compareIgnoreCase (*this, other);
}
/** Compares this string with another one. */
int compareIgnoreCase (const CharPointer_UTF8 other) const noexcept
{
#if JUCE_WINDOWS
return stricmp (data, other.data);
#else
return strcasecmp (data, other.data);
#endif
}
/** Compares this string with another one, up to a specified number of characters. */
template <typename CharPointer>
int compareIgnoreCaseUpTo (const CharPointer other, const int maxChars) const noexcept
{
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
}
/** Returns the character index of a substring, or -1 if it isn't found. */
template <typename CharPointer>
int indexOf (const CharPointer stringToFind) const noexcept
{
return CharacterFunctions::indexOf (*this, stringToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind) const noexcept
{
return CharacterFunctions::indexOfChar (*this, charToFind);
}
/** Returns the character index of a unicode character, or -1 if it isn't found. */
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
{
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
: CharacterFunctions::indexOfChar (*this, charToFind);
}
/** Returns true if the first character of this string is whitespace. */
bool isWhitespace() const noexcept { return *data == ' ' || (*data <= 13 && *data >= 9); }
/** Returns true if the first character of this string is a digit. */
bool isDigit() const noexcept { return *data >= '0' && *data <= '9'; }
/** Returns true if the first character of this string is a letter. */
bool isLetter() const noexcept { return CharacterFunctions::isLetter (operator*()) != 0; }
/** Returns true if the first character of this string is a letter or digit. */
bool isLetterOrDigit() const noexcept { return CharacterFunctions::isLetterOrDigit (operator*()) != 0; }
/** Returns true if the first character of this string is upper-case. */
bool isUpperCase() const noexcept { return CharacterFunctions::isUpperCase (operator*()) != 0; }
/** Returns true if the first character of this string is lower-case. */
bool isLowerCase() const noexcept { return CharacterFunctions::isLowerCase (operator*()) != 0; }
/** Returns an upper-case version of the first character of this string. */
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (operator*()); }
/** Returns a lower-case version of the first character of this string. */
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (operator*()); }
/** Parses this string as a 32-bit integer. */
int getIntValue32() const noexcept { return atoi (data); }
/** Parses this string as a 64-bit integer. */
int64 getIntValue64() const noexcept
{
#if JUCE_LINUX || JUCE_ANDROID
return atoll (data);
#elif JUCE_WINDOWS
return _atoi64 (data);
#else
return CharacterFunctions::getIntValue <int64, CharPointer_UTF8> (*this);
#endif
}
/** Parses this string as a floating point double. */
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF8 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
/** Returns true if the given unicode character can be represented in this encoding. */
static bool canRepresent (juce_wchar character) noexcept
{
return ((unsigned int) character) < (unsigned int) 0x10ffff;
}
/** Returns true if this data contains a valid string in this encoding. */
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
{
while (--maxBytesToRead >= 0 && *dataToTest != 0)
{
const signed char byte = (signed char) *dataToTest++;
if (byte < 0)
{
uint8 bit = 0x40;
int numExtraValues = 0;
while ((byte & bit) != 0)
{
if (bit < 8)
return false;
++numExtraValues;
bit >>= 1;
if (bit == 8 && (numExtraValues > maxBytesToRead
|| *CharPointer_UTF8 (dataToTest - 1) > 0x10ffff))
return false;
}
maxBytesToRead -= numExtraValues;
if (maxBytesToRead < 0)
return false;
while (--numExtraValues >= 0)
if ((*dataToTest++ & 0xc0) != 0x80)
return false;
}
}
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF8 atomicSwap (const CharPointer_UTF8 newValue)
{
return CharPointer_UTF8 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
}
/** These values are the byte-order mark (BOM) values for a UTF-8 stream. */
enum
{
byteOrderMark1 = 0xef,
byteOrderMark2 = 0xbb,
byteOrderMark3 = 0xbf
};
/** Returns true if the first three bytes in this pointer are the UTF8 byte-order mark (BOM).
The pointer must not be null, and must point to at least 3 valid bytes.
*/
static bool isByteOrderMark (const void* possibleByteOrder) noexcept
{
jassert (possibleByteOrder != nullptr);
const uint8* const c = static_cast<const uint8*> (possibleByteOrder);
return c[0] == (uint8) byteOrderMark1
&& c[1] == (uint8) byteOrderMark2
&& c[2] == (uint8) byteOrderMark3;
}
private:
CharType* data;
};
#endif // JUCE_CHARPOINTER_UTF8_H_INCLUDED
@@ -0,0 +1,154 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
//==============================================================================
#if JUCE_MSVC
#pragma warning (push)
#pragma warning (disable: 4514 4996)
#endif
juce_wchar CharacterFunctions::toUpperCase (const juce_wchar character) noexcept
{
return towupper ((wchar_t) character);
}
juce_wchar CharacterFunctions::toLowerCase (const juce_wchar character) noexcept
{
return towlower ((wchar_t) character);
}
bool CharacterFunctions::isUpperCase (const juce_wchar character) noexcept
{
#if JUCE_WINDOWS
return iswupper ((wchar_t) character) != 0;
#else
return toLowerCase (character) != character;
#endif
}
bool CharacterFunctions::isLowerCase (const juce_wchar character) noexcept
{
#if JUCE_WINDOWS
return iswlower ((wchar_t) character) != 0;
#else
return toUpperCase (character) != character;
#endif
}
#if JUCE_MSVC
#pragma warning (pop)
#endif
//==============================================================================
bool CharacterFunctions::isWhitespace (const char character) noexcept
{
return character == ' ' || (character <= 13 && character >= 9);
}
bool CharacterFunctions::isWhitespace (const juce_wchar character) noexcept
{
return iswspace ((wchar_t) character) != 0;
}
bool CharacterFunctions::isDigit (const char character) noexcept
{
return (character >= '0' && character <= '9');
}
bool CharacterFunctions::isDigit (const juce_wchar character) noexcept
{
return iswdigit ((wchar_t) character) != 0;
}
bool CharacterFunctions::isLetter (const char character) noexcept
{
return (character >= 'a' && character <= 'z')
|| (character >= 'A' && character <= 'Z');
}
bool CharacterFunctions::isLetter (const juce_wchar character) noexcept
{
return iswalpha ((wchar_t) character) != 0;
}
bool CharacterFunctions::isLetterOrDigit (const char character) noexcept
{
return (character >= 'a' && character <= 'z')
|| (character >= 'A' && character <= 'Z')
|| (character >= '0' && character <= '9');
}
bool CharacterFunctions::isLetterOrDigit (const juce_wchar character) noexcept
{
return iswalnum ((wchar_t) character) != 0;
}
int CharacterFunctions::getHexDigitValue (const juce_wchar digit) noexcept
{
unsigned int d = (unsigned int) digit - '0';
if (d < (unsigned int) 10)
return (int) d;
d += (unsigned int) ('0' - 'a');
if (d < (unsigned int) 6)
return (int) d + 10;
d += (unsigned int) ('a' - 'A');
if (d < (unsigned int) 6)
return (int) d + 10;
return -1;
}
double CharacterFunctions::mulexp10 (const double value, int exponent) noexcept
{
if (exponent == 0)
return value;
if (value == 0)
return 0;
const bool negative = (exponent < 0);
if (negative)
exponent = -exponent;
double result = 1.0, power = 10.0;
for (int bit = 1; exponent != 0; bit <<= 1)
{
if ((exponent & bit) != 0)
{
exponent ^= bit;
result *= power;
if (exponent == 0)
break;
}
power *= power;
}
return negative ? (value / result) : (value * result);
}
@@ -0,0 +1,629 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_CHARACTERFUNCTIONS_H_INCLUDED
#define JUCE_CHARACTERFUNCTIONS_H_INCLUDED
//==============================================================================
#if JUCE_WINDOWS && ! DOXYGEN
#define JUCE_NATIVE_WCHAR_IS_UTF8 0
#define JUCE_NATIVE_WCHAR_IS_UTF16 1
#define JUCE_NATIVE_WCHAR_IS_UTF32 0
#else
/** This macro will be set to 1 if the compiler's native wchar_t is an 8-bit type. */
#define JUCE_NATIVE_WCHAR_IS_UTF8 0
/** This macro will be set to 1 if the compiler's native wchar_t is a 16-bit type. */
#define JUCE_NATIVE_WCHAR_IS_UTF16 0
/** This macro will be set to 1 if the compiler's native wchar_t is a 32-bit type. */
#define JUCE_NATIVE_WCHAR_IS_UTF32 1
#endif
#if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
/** A platform-independent 32-bit unicode character type. */
typedef wchar_t juce_wchar;
#else
typedef uint32 juce_wchar;
#endif
#ifndef DOXYGEN
/** This macro is deprecated, but preserved for compatibility with old code. */
#define JUCE_T(stringLiteral) (L##stringLiteral)
#endif
#if JUCE_DEFINE_T_MACRO
/** The 'T' macro is an alternative for using the "L" prefix in front of a string literal.
This macro is deprecated, but available for compatibility with old code if you set
JUCE_DEFINE_T_MACRO = 1. The fastest, most portable and best way to write your string
literals is as standard char strings, using escaped utf-8 character sequences for extended
characters, rather than trying to store them as wide-char strings.
*/
#define T(stringLiteral) JUCE_T(stringLiteral)
#endif
//==============================================================================
/**
A collection of functions for manipulating characters and character strings.
Most of these methods are designed for internal use by the String and CharPointer
classes, but some of them may be useful to call directly.
@see String, CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
*/
class JUCE_API CharacterFunctions
{
public:
//==============================================================================
/** Converts a character to upper-case. */
static juce_wchar toUpperCase (juce_wchar character) noexcept;
/** Converts a character to lower-case. */
static juce_wchar toLowerCase (juce_wchar character) noexcept;
/** Checks whether a unicode character is upper-case. */
static bool isUpperCase (juce_wchar character) noexcept;
/** Checks whether a unicode character is lower-case. */
static bool isLowerCase (juce_wchar character) noexcept;
/** Checks whether a character is whitespace. */
static bool isWhitespace (char character) noexcept;
/** Checks whether a character is whitespace. */
static bool isWhitespace (juce_wchar character) noexcept;
/** Checks whether a character is a digit. */
static bool isDigit (char character) noexcept;
/** Checks whether a character is a digit. */
static bool isDigit (juce_wchar character) noexcept;
/** Checks whether a character is alphabetic. */
static bool isLetter (char character) noexcept;
/** Checks whether a character is alphabetic. */
static bool isLetter (juce_wchar character) noexcept;
/** Checks whether a character is alphabetic or numeric. */
static bool isLetterOrDigit (char character) noexcept;
/** Checks whether a character is alphabetic or numeric. */
static bool isLetterOrDigit (juce_wchar character) noexcept;
/** Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit. */
static int getHexDigitValue (juce_wchar digit) noexcept;
//==============================================================================
/** Parses a character string to read a floating-point number.
Note that this will advance the pointer that is passed in, leaving it at
the end of the number.
*/
template <typename CharPointerType>
static double readDoubleValue (CharPointerType& text) noexcept
{
double result[3] = { 0 }, accumulator[2] = { 0 };
int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
int exponent = 0, decPointIndex = 0, digit = 0;
int lastDigit = 0, numSignificantDigits = 0;
bool isNegative = false, digitsFound = false;
const int maxSignificantDigits = 15 + 2;
text = text.findEndOfWhitespace();
juce_wchar c = *text;
switch (c)
{
case '-': isNegative = true; // fall-through..
case '+': c = *++text;
}
switch (c)
{
case 'n':
case 'N':
if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N'))
return std::numeric_limits<double>::quiet_NaN();
break;
case 'i':
case 'I':
if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F'))
return std::numeric_limits<double>::infinity();
break;
}
for (;;)
{
if (text.isDigit())
{
lastDigit = digit;
digit = (int) text.getAndAdvance() - '0';
digitsFound = true;
if (decPointIndex != 0)
exponentAdjustment[1]++;
if (numSignificantDigits == 0 && digit == 0)
continue;
if (++numSignificantDigits > maxSignificantDigits)
{
if (digit > 5)
++accumulator [decPointIndex];
else if (digit == 5 && (lastDigit & 1) != 0)
++accumulator [decPointIndex];
if (decPointIndex > 0)
exponentAdjustment[1]--;
else
exponentAdjustment[0]++;
while (text.isDigit())
{
++text;
if (decPointIndex == 0)
exponentAdjustment[0]++;
}
}
else
{
const double maxAccumulatorValue = (double) ((std::numeric_limits<unsigned int>::max() - 9) / 10);
if (accumulator [decPointIndex] > maxAccumulatorValue)
{
result [decPointIndex] = mulexp10 (result [decPointIndex], exponentAccumulator [decPointIndex])
+ accumulator [decPointIndex];
accumulator [decPointIndex] = 0;
exponentAccumulator [decPointIndex] = 0;
}
accumulator [decPointIndex] = accumulator[decPointIndex] * 10 + digit;
exponentAccumulator [decPointIndex]++;
}
}
else if (decPointIndex == 0 && *text == '.')
{
++text;
decPointIndex = 1;
if (numSignificantDigits > maxSignificantDigits)
{
while (text.isDigit())
++text;
break;
}
}
else
{
break;
}
}
result[0] = mulexp10 (result[0], exponentAccumulator[0]) + accumulator[0];
if (decPointIndex != 0)
result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1];
c = *text;
if ((c == 'e' || c == 'E') && digitsFound)
{
bool negativeExponent = false;
switch (*++text)
{
case '-': negativeExponent = true; // fall-through..
case '+': ++text;
}
while (text.isDigit())
exponent = (exponent * 10) + ((int) text.getAndAdvance() - '0');
if (negativeExponent)
exponent = -exponent;
}
double r = mulexp10 (result[0], exponent + exponentAdjustment[0]);
if (decPointIndex != 0)
r += mulexp10 (result[1], exponent - exponentAdjustment[1]);
return isNegative ? -r : r;
}
/** Parses a character string, to read a floating-point value. */
template <typename CharPointerType>
static double getDoubleValue (CharPointerType text) noexcept
{
return readDoubleValue (text);
}
//==============================================================================
/** Parses a character string, to read an integer value. */
template <typename IntType, typename CharPointerType>
static IntType getIntValue (const CharPointerType text) noexcept
{
IntType v = 0;
CharPointerType s (text.findEndOfWhitespace());
const bool isNeg = *s == '-';
if (isNeg)
++s;
for (;;)
{
const juce_wchar c = s.getAndAdvance();
if (c >= '0' && c <= '9')
v = v * 10 + (IntType) (c - '0');
else
break;
}
return isNeg ? -v : v;
}
template <typename ResultType>
struct HexParser
{
template <typename CharPointerType>
static ResultType parse (CharPointerType t) noexcept
{
ResultType result = 0;
while (! t.isEmpty())
{
const int hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
if (hexValue >= 0)
result = (result << 4) | hexValue;
}
return result;
}
};
//==============================================================================
/** Counts the number of characters in a given string, stopping if the count exceeds
a specified limit. */
template <typename CharPointerType>
static size_t lengthUpTo (CharPointerType text, const size_t maxCharsToCount) noexcept
{
size_t len = 0;
while (len < maxCharsToCount && text.getAndAdvance() != 0)
++len;
return len;
}
/** Counts the number of characters in a given string, stopping if the count exceeds
a specified end-pointer. */
template <typename CharPointerType>
static size_t lengthUpTo (CharPointerType start, const CharPointerType end) noexcept
{
size_t len = 0;
while (start < end && start.getAndAdvance() != 0)
++len;
return len;
}
/** Copies null-terminated characters from one string to another. */
template <typename DestCharPointerType, typename SrcCharPointerType>
static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) noexcept
{
for (;;)
{
const juce_wchar c = src.getAndAdvance();
if (c == 0)
break;
dest.write (c);
}
dest.writeNull();
}
/** Copies characters from one string to another, up to a null terminator
or a given byte size limit. */
template <typename DestCharPointerType, typename SrcCharPointerType>
static size_t copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, size_t maxBytesToWrite) noexcept
{
typename DestCharPointerType::CharType const* const startAddress = dest.getAddress();
ssize_t maxBytes = (ssize_t) maxBytesToWrite;
maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null)
for (;;)
{
const juce_wchar c = src.getAndAdvance();
const size_t bytesNeeded = DestCharPointerType::getBytesRequiredFor (c);
maxBytes -= bytesNeeded;
if (c == 0 || maxBytes < 0)
break;
dest.write (c);
}
dest.writeNull();
return (size_t) getAddressDifference (dest.getAddress(), startAddress)
+ sizeof (typename DestCharPointerType::CharType);
}
/** Copies characters from one string to another, up to a null terminator
or a given maximum number of characters. */
template <typename DestCharPointerType, typename SrcCharPointerType>
static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) noexcept
{
while (--maxChars > 0)
{
const juce_wchar c = src.getAndAdvance();
if (c == 0)
break;
dest.write (c);
}
dest.writeNull();
}
/** Compares two null-terminated character strings. */
template <typename CharPointerType1, typename CharPointerType2>
static int compare (CharPointerType1 s1, CharPointerType2 s2) noexcept
{
for (;;)
{
const int c1 = (int) s1.getAndAdvance();
const int c2 = (int) s2.getAndAdvance();
const int diff = c1 - c2;
if (diff != 0) return diff < 0 ? -1 : 1;
if (c1 == 0) break;
}
return 0;
}
/** Compares two null-terminated character strings, up to a given number of characters. */
template <typename CharPointerType1, typename CharPointerType2>
static int compareUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
{
while (--maxChars >= 0)
{
const int c1 = (int) s1.getAndAdvance();
const int c2 = (int) s2.getAndAdvance();
const int diff = c1 - c2;
if (diff != 0) return diff < 0 ? -1 : 1;
if (c1 == 0) break;
}
return 0;
}
/** Compares two null-terminated character strings, using a case-independant match. */
template <typename CharPointerType1, typename CharPointerType2>
static int compareIgnoreCase (CharPointerType1 s1, CharPointerType2 s2) noexcept
{
for (;;)
{
const int c1 = (int) s1.toUpperCase();
const int c2 = (int) s2.toUpperCase();
const int diff = c1 - c2;
if (diff != 0) return diff < 0 ? -1 : 1;
if (c1 == 0) break;
++s1; ++s2;
}
return 0;
}
/** Compares two null-terminated character strings, using a case-independent match. */
template <typename CharPointerType1, typename CharPointerType2>
static int compareIgnoreCaseUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
{
while (--maxChars >= 0)
{
const int c1 = (int) s1.toUpperCase();
const int c2 = (int) s2.toUpperCase();
const int diff = c1 - c2;
if (diff != 0) return diff < 0 ? -1 : 1;
if (c1 == 0) break;
++s1; ++s2;
}
return 0;
}
/** Finds the character index of a given substring in another string.
Returns -1 if the substring is not found.
*/
template <typename CharPointerType1, typename CharPointerType2>
static int indexOf (CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
{
int index = 0;
const int substringLength = (int) substringToLookFor.length();
for (;;)
{
if (textToSearch.compareUpTo (substringToLookFor, substringLength) == 0)
return index;
if (textToSearch.getAndAdvance() == 0)
return -1;
++index;
}
}
/** Returns a pointer to the first occurrence of a substring in a string.
If the substring is not found, this will return a pointer to the string's
null terminator.
*/
template <typename CharPointerType1, typename CharPointerType2>
static CharPointerType1 find (CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
{
const int substringLength = (int) substringToLookFor.length();
while (textToSearch.compareUpTo (substringToLookFor, substringLength) != 0
&& ! textToSearch.isEmpty())
++textToSearch;
return textToSearch;
}
/** Returns a pointer to the first occurrence of a substring in a string.
If the substring is not found, this will return a pointer to the string's
null terminator.
*/
template <typename CharPointerType>
static CharPointerType find (CharPointerType textToSearch, const juce_wchar charToLookFor) noexcept
{
for (;; ++textToSearch)
{
const juce_wchar c = *textToSearch;
if (c == charToLookFor || c == 0)
break;
}
return textToSearch;
}
/** Finds the character index of a given substring in another string, using
a case-independent match.
Returns -1 if the substring is not found.
*/
template <typename CharPointerType1, typename CharPointerType2>
static int indexOfIgnoreCase (CharPointerType1 haystack, const CharPointerType2 needle) noexcept
{
int index = 0;
const int needleLength = (int) needle.length();
for (;;)
{
if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
return index;
if (haystack.getAndAdvance() == 0)
return -1;
++index;
}
}
/** Finds the character index of a given character in another string.
Returns -1 if the character is not found.
*/
template <typename Type>
static int indexOfChar (Type text, const juce_wchar charToFind) noexcept
{
int i = 0;
while (! text.isEmpty())
{
if (text.getAndAdvance() == charToFind)
return i;
++i;
}
return -1;
}
/** Finds the character index of a given character in another string, using
a case-independent match.
Returns -1 if the character is not found.
*/
template <typename Type>
static int indexOfCharIgnoreCase (Type text, juce_wchar charToFind) noexcept
{
charToFind = CharacterFunctions::toLowerCase (charToFind);
int i = 0;
while (! text.isEmpty())
{
if (text.toLowerCase() == charToFind)
return i;
++text;
++i;
}
return -1;
}
/** Returns a pointer to the first non-whitespace character in a string.
If the string contains only whitespace, this will return a pointer
to its null terminator.
*/
template <typename Type>
static Type findEndOfWhitespace (Type text) noexcept
{
while (text.isWhitespace())
++text;
return text;
}
/** Returns a pointer to the first character in the string which is found in
the breakCharacters string.
*/
template <typename Type, typename BreakType>
static Type findEndOfToken (Type text, const BreakType breakCharacters, const Type quoteCharacters)
{
juce_wchar currentQuoteChar = 0;
while (! text.isEmpty())
{
const juce_wchar c = text.getAndAdvance();
if (currentQuoteChar == 0 && breakCharacters.indexOf (c) >= 0)
{
--text;
break;
}
if (quoteCharacters.indexOf (c) >= 0)
{
if (currentQuoteChar == 0)
currentQuoteChar = c;
else if (currentQuoteChar == c)
currentQuoteChar = 0;
}
}
return text;
}
private:
static double mulexp10 (const double value, int exponent) noexcept;
};
#endif // JUCE_CHARACTERFUNCTIONS_H_INCLUDED
@@ -0,0 +1,70 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
Identifier::Identifier() noexcept {}
Identifier::~Identifier() noexcept {}
Identifier::Identifier (const Identifier& other) noexcept : name (other.name) {}
Identifier& Identifier::operator= (const Identifier other) noexcept
{
name = other.name;
return *this;
}
Identifier::Identifier (const String& nm)
: name (StringPool::getGlobalPool().getPooledString (nm))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
}
Identifier::Identifier (const char* nm)
: name (StringPool::getGlobalPool().getPooledString (nm))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
}
Identifier::Identifier (String::CharPointerType start, String::CharPointerType end)
: name (StringPool::getGlobalPool().getPooledString (start, end))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
}
Identifier Identifier::null;
bool Identifier::isValidIdentifier (const String& possibleIdentifier) noexcept
{
return possibleIdentifier.isNotEmpty()
&& possibleIdentifier.containsOnly ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:#@$%");
}
@@ -0,0 +1,120 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_IDENTIFIER_H_INCLUDED
#define JUCE_IDENTIFIER_H_INCLUDED
//==============================================================================
/**
Represents a string identifier, designed for accessing properties by name.
Comparing two Identifier objects is very fast (an O(1) operation), but creating
them can be slower than just using a String directly, so the optimal way to use them
is to keep some static Identifier objects for the things you use often.
@see NamedValueSet, ValueTree
*/
class JUCE_API Identifier
{
public:
/** Creates a null identifier. */
Identifier() noexcept;
/** Creates an identifier with a specified name.
Because this name may need to be used in contexts such as script variables or XML
tags, it must only contain ascii letters and digits, or the underscore character.
*/
Identifier (const char* name);
/** Creates an identifier with a specified name.
Because this name may need to be used in contexts such as script variables or XML
tags, it must only contain ascii letters and digits, or the underscore character.
*/
Identifier (const String& name);
/** Creates an identifier with a specified name.
Because this name may need to be used in contexts such as script variables or XML
tags, it must only contain ascii letters and digits, or the underscore character.
*/
Identifier (String::CharPointerType nameStart, String::CharPointerType nameEnd);
/** Creates a copy of another identifier. */
Identifier (const Identifier& other) noexcept;
/** Creates a copy of another identifier. */
Identifier& operator= (const Identifier other) noexcept;
/** Destructor */
~Identifier() noexcept;
/** Compares two identifiers. This is a very fast operation. */
inline bool operator== (Identifier other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); }
/** Compares two identifiers. This is a very fast operation. */
inline bool operator!= (Identifier other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); }
/** Compares the identifier with a string. */
inline bool operator== (StringRef other) const noexcept { return name == other; }
/** Compares the identifier with a string. */
inline bool operator!= (StringRef other) const noexcept { return name != other; }
/** Returns this identifier as a string. */
const String& toString() const noexcept { return name; }
/** Returns this identifier's raw string pointer. */
operator String::CharPointerType() const noexcept { return name.getCharPointer(); }
/** Returns this identifier's raw string pointer. */
String::CharPointerType getCharPointer() const noexcept { return name.getCharPointer(); }
/** Returns this identifier as a StringRef. */
operator StringRef() const noexcept { return name; }
/** Returns true if this Identifier is not null */
bool isValid() const noexcept { return name.isNotEmpty(); }
/** Returns true if this Identifier is null */
bool isNull() const noexcept { return name.isEmpty(); }
/** A null identifier. */
static Identifier null;
/** Checks a given string for characters that might not be valid in an Identifier.
Since Identifiers are used as a script variables and XML attributes, they should only contain
alphanumeric characters, underscores, or the '-' and ':' characters.
*/
static bool isValidIdentifier (const String& possibleIdentifier) noexcept;
private:
String name;
};
#endif // JUCE_IDENTIFIER_H_INCLUDED
@@ -0,0 +1,209 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
LocalisedStrings::LocalisedStrings (const String& fileContents, bool ignoreCase)
{
loadFromText (fileContents, ignoreCase);
}
LocalisedStrings::LocalisedStrings (const File& fileToLoad, bool ignoreCase)
{
loadFromText (fileToLoad.loadFileAsString(), ignoreCase);
}
LocalisedStrings::LocalisedStrings (const LocalisedStrings& other)
: languageName (other.languageName), countryCodes (other.countryCodes),
translations (other.translations), fallback (createCopyIfNotNull (other.fallback.get()))
{
}
LocalisedStrings& LocalisedStrings::operator= (const LocalisedStrings& other)
{
languageName = other.languageName;
countryCodes = other.countryCodes;
translations = other.translations;
fallback = createCopyIfNotNull (other.fallback.get());
return *this;
}
LocalisedStrings::~LocalisedStrings()
{
}
//==============================================================================
String LocalisedStrings::translate (const String& text) const
{
if (fallback != nullptr && ! translations.containsKey (text))
return fallback->translate (text);
return translations.getValue (text, text);
}
String LocalisedStrings::translate (const String& text, const String& resultIfNotFound) const
{
if (fallback != nullptr && ! translations.containsKey (text))
return fallback->translate (text, resultIfNotFound);
return translations.getValue (text, resultIfNotFound);
}
namespace
{
#if JUCE_CHECK_MEMORY_LEAKS
// By using this object to force a LocalisedStrings object to be created
// before the currentMappings object, we can force the static order-of-destruction to
// delete the currentMappings object first, which avoids a bogus leak warning.
// (Oddly, just creating a LocalisedStrings on the stack doesn't work in gcc, it
// has to be created with 'new' for this to work..)
struct LeakAvoidanceTrick
{
LeakAvoidanceTrick()
{
const ScopedPointer<LocalisedStrings> dummy (new LocalisedStrings (String(), false));
}
};
LeakAvoidanceTrick leakAvoidanceTrick;
#endif
SpinLock currentMappingsLock;
ScopedPointer<LocalisedStrings> currentMappings;
static int findCloseQuote (const String& text, int startPos)
{
juce_wchar lastChar = 0;
String::CharPointerType t (text.getCharPointer() + startPos);
for (;;)
{
const juce_wchar c = t.getAndAdvance();
if (c == 0 || (c == '"' && lastChar != '\\'))
break;
lastChar = c;
++startPos;
}
return startPos;
}
static String unescapeString (const String& s)
{
return s.replace ("\\\"", "\"")
.replace ("\\\'", "\'")
.replace ("\\t", "\t")
.replace ("\\r", "\r")
.replace ("\\n", "\n");
}
}
void LocalisedStrings::loadFromText (const String& fileContents, bool ignoreCase)
{
translations.setIgnoresCase (ignoreCase);
StringArray lines;
lines.addLines (fileContents);
for (int i = 0; i < lines.size(); ++i)
{
String line (lines[i].trim());
if (line.startsWithChar ('"'))
{
int closeQuote = findCloseQuote (line, 1);
const String originalText (unescapeString (line.substring (1, closeQuote)));
if (originalText.isNotEmpty())
{
const int openingQuote = findCloseQuote (line, closeQuote + 1);
closeQuote = findCloseQuote (line, openingQuote + 1);
const String newText (unescapeString (line.substring (openingQuote + 1, closeQuote)));
if (newText.isNotEmpty())
translations.set (originalText, newText);
}
}
else if (line.startsWithIgnoreCase ("language:"))
{
languageName = line.substring (9).trim();
}
else if (line.startsWithIgnoreCase ("countries:"))
{
countryCodes.addTokens (line.substring (10).trim(), true);
countryCodes.trim();
countryCodes.removeEmptyStrings();
}
}
translations.minimiseStorageOverheads();
}
void LocalisedStrings::addStrings (const LocalisedStrings& other)
{
jassert (languageName == other.languageName);
jassert (countryCodes == other.countryCodes);
translations.addArray (other.translations);
}
void LocalisedStrings::setFallback (LocalisedStrings* f)
{
fallback = f;
}
//==============================================================================
void LocalisedStrings::setCurrentMappings (LocalisedStrings* newTranslations)
{
const SpinLock::ScopedLockType sl (currentMappingsLock);
currentMappings = newTranslations;
}
LocalisedStrings* LocalisedStrings::getCurrentMappings()
{
return currentMappings;
}
String LocalisedStrings::translateWithCurrentMappings (const String& text) { return juce::translate (text); }
String LocalisedStrings::translateWithCurrentMappings (const char* text) { return juce::translate (text); }
JUCE_API String translate (const String& text) { return juce::translate (text, text); }
JUCE_API String translate (const char* text) { return juce::translate (String (text)); }
JUCE_API String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
JUCE_API String translate (const String& text, const String& resultIfNotFound)
{
const SpinLock::ScopedLockType sl (currentMappingsLock);
if (const LocalisedStrings* const mappings = LocalisedStrings::getCurrentMappings())
return mappings->translate (text, resultIfNotFound);
return resultIfNotFound;
}
@@ -0,0 +1,247 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_LOCALISEDSTRINGS_H_INCLUDED
#define JUCE_LOCALISEDSTRINGS_H_INCLUDED
//==============================================================================
/**
Used to convert strings to localised foreign-language versions.
This is basically a look-up table of strings and their translated equivalents.
It can be loaded from a text file, so that you can supply a set of localised
versions of strings that you use in your app.
To use it in your code, simply call the translate() method on each string that
might have foreign versions, and if none is found, the method will just return
the original string.
The translation file should start with some lines specifying a description of
the language it contains, and also a list of ISO country codes where it might
be appropriate to use the file. After that, each line of the file should contain
a pair of quoted strings with an '=' sign.
E.g. for a french translation, the file might be:
@code
language: French
countries: fr be mc ch lu
"hello" = "bonjour"
"goodbye" = "au revoir"
@endcode
If the strings need to contain a quote character, they can use '\"' instead, and
if the first non-whitespace character on a line isn't a quote, then it's ignored,
(you can use this to add comments).
Note that this is a singleton class, so don't create or destroy the object directly.
There's also a TRANS(text) macro defined to make it easy to use the this.
E.g. @code
printSomething (TRANS("hello"));
@endcode
This macro is used in the Juce classes themselves, so your application has a chance to
intercept and translate any internal Juce text strings that might be shown. (You can easily
get a list of all the messages by searching for the TRANS() macro in the Juce source
code).
*/
class JUCE_API LocalisedStrings
{
public:
//==============================================================================
/** Creates a set of translations from the text of a translation file.
When you create one of these, you can call setCurrentMappings() to make it
the set of mappings that the system's using.
*/
LocalisedStrings (const String& fileContents, bool ignoreCaseOfKeys);
/** Creates a set of translations from a file.
When you create one of these, you can call setCurrentMappings() to make it
the set of mappings that the system's using.
*/
LocalisedStrings (const File& fileToLoad, bool ignoreCaseOfKeys);
LocalisedStrings (const LocalisedStrings&);
LocalisedStrings& operator= (const LocalisedStrings&);
/** Destructor. */
~LocalisedStrings();
//==============================================================================
/** Selects the current set of mappings to be used by the system.
The object you pass in will be automatically deleted when no longer needed, so
don't keep a pointer to it. You can also pass in nullptr to remove the current
mappings.
See also the TRANS() macro, which uses the current set to do its translation.
@see translateWithCurrentMappings
*/
static void setCurrentMappings (LocalisedStrings* newTranslations);
/** Returns the currently selected set of mappings.
This is the object that was last passed to setCurrentMappings(). It may
be nullptr if none has been created.
*/
static LocalisedStrings* getCurrentMappings();
/** Tries to translate a string using the currently selected set of mappings.
If no mapping has been set, or if the mapping doesn't contain a translation
for the string, this will just return the original string.
See also the TRANS() macro, which uses this method to do its translation.
@see setCurrentMappings, getCurrentMappings
*/
static String translateWithCurrentMappings (const String& text);
/** Tries to translate a string using the currently selected set of mappings.
If no mapping has been set, or if the mapping doesn't contain a translation
for the string, this will just return the original string.
See also the TRANS() macro, which uses this method to do its translation.
@see setCurrentMappings, getCurrentMappings
*/
static String translateWithCurrentMappings (const char* text);
//==============================================================================
/** Attempts to look up a string and return its localised version.
If the string isn't found in the list, the original string will be returned.
*/
String translate (const String& text) const;
/** Attempts to look up a string and return its localised version.
If the string isn't found in the list, the resultIfNotFound string will be returned.
*/
String translate (const String& text, const String& resultIfNotFound) const;
/** Returns the name of the language specified in the translation file.
This is specified in the file using a line starting with "language:", e.g.
@code
language: german
@endcode
*/
String getLanguageName() const { return languageName; }
/** Returns the list of suitable country codes listed in the translation file.
These is specified in the file using a line starting with "countries:", e.g.
@code
countries: fr be mc ch lu
@endcode
The country codes are supposed to be 2-character ISO complient codes.
*/
const StringArray& getCountryCodes() const { return countryCodes; }
/** Provides access to the actual list of mappings. */
const StringPairArray& getMappings() const { return translations; }
//==============================================================================
/** Adds and merges another set of translations into this set.
Note that the language name and country codes of the new LocalisedStrings
object must match that of this object - an assertion will be thrown if they
don't match.
Any existing values will have their mappings overwritten by the new ones.
*/
void addStrings (const LocalisedStrings&);
/** Gives this object a set of strings to use as a fallback if a string isn't found.
The object that is passed-in will be owned and deleted by this object
when no longer needed. It can be nullptr to clear the existing fallback object.
*/
void setFallback (LocalisedStrings* fallbackStrings);
private:
//==============================================================================
String languageName;
StringArray countryCodes;
StringPairArray translations;
ScopedPointer<LocalisedStrings> fallback;
friend struct ContainerDeletePolicy<LocalisedStrings>;
void loadFromText (const String&, bool ignoreCase);
JUCE_LEAK_DETECTOR (LocalisedStrings)
};
//==============================================================================
#ifndef TRANS
/** Uses the LocalisedStrings class to translate the given string literal.
This macro is provided for backwards-compatibility, and just calls the translate()
function. In new code, it's recommended that you just call translate() directly
instead, and avoid using macros.
@see translate(), LocalisedStrings
*/
#define TRANS(stringLiteral) juce::translate (stringLiteral)
#endif
/** A dummy version of the TRANS macro, used to indicate a string literal that should be
added to the translation file by source-code scanner tools.
Wrapping a string literal in this macro has no effect, but by using it around strings
that your app needs to translate at a later stage, it lets automatic code-scanning tools
find this string and add it to the list of strings that need translation.
*/
#define NEEDS_TRANS(stringLiteral) (stringLiteral)
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate (const String& stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate (const char* stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate (CharPointer_UTF8 stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
JUCE_API String translate (const String& stringLiteral, const String& resultIfNotFound);
#endif // JUCE_LOCALISEDSTRINGS_H_INCLUDED
@@ -0,0 +1,86 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_NEWLINE_H_INCLUDED
#define JUCE_NEWLINE_H_INCLUDED
//==============================================================================
/** This class is used for represent a new-line character sequence.
To write a new-line to a stream, you can use the predefined 'newLine' variable, e.g.
@code
myOutputStream << "Hello World" << newLine << newLine;
@endcode
The exact character sequence that will be used for the new-line can be set and
retrieved with OutputStream::setNewLineString() and OutputStream::getNewLineString().
*/
class JUCE_API NewLine
{
public:
/** Returns the default new-line sequence that the library uses.
@see OutputStream::setNewLineString()
*/
static const char* getDefault() noexcept { return "\r\n"; }
/** Returns the default new-line sequence that the library uses.
@see getDefault()
*/
operator String() const { return getDefault(); }
/** Returns the default new-line sequence that the library uses.
@see OutputStream::setNewLineString()
*/
operator StringRef() const noexcept { return getDefault(); }
};
//==============================================================================
/** A predefined object representing a new-line, which can be written to a string or stream.
To write a new-line to a stream, you can use the predefined 'newLine' variable like this:
@code
myOutputStream << "Hello World" << newLine << newLine;
@endcode
*/
extern NewLine newLine;
//==============================================================================
/** Writes a new-line sequence to a string.
You can use the predefined object 'newLine' to invoke this, e.g.
@code
myString << "Hello World" << newLine << newLine;
@endcode
*/
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const NewLine&);
#if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN)
inline String operator+ (String s1, const NewLine&) { return s1 += NewLine::getDefault(); }
#endif
#endif // JUCE_NEWLINE_H_INCLUDED
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,485 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
StringArray::StringArray() noexcept
{
}
StringArray::StringArray (const StringArray& other)
: strings (other.strings)
{
}
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray::StringArray (StringArray&& other) noexcept
: strings (static_cast <Array <String>&&> (other.strings))
{
}
#endif
StringArray::StringArray (const String& firstValue)
{
strings.add (firstValue);
}
StringArray::StringArray (const String* initialStrings, int numberOfStrings)
{
strings.addArray (initialStrings, numberOfStrings);
}
StringArray::StringArray (const char* const* initialStrings)
{
strings.addNullTerminatedArray (initialStrings);
}
StringArray::StringArray (const char* const* initialStrings, int numberOfStrings)
{
strings.addArray (initialStrings, numberOfStrings);
}
StringArray::StringArray (const wchar_t* const* initialStrings)
{
strings.addNullTerminatedArray (initialStrings);
}
StringArray::StringArray (const wchar_t* const* initialStrings, int numberOfStrings)
{
strings.addArray (initialStrings, numberOfStrings);
}
StringArray& StringArray::operator= (const StringArray& other)
{
strings = other.strings;
return *this;
}
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray& StringArray::operator= (StringArray&& other) noexcept
{
strings = static_cast <Array<String>&&> (other.strings);
return *this;
}
#endif
StringArray::~StringArray()
{
}
bool StringArray::operator== (const StringArray& other) const noexcept
{
return strings == other.strings;
}
bool StringArray::operator!= (const StringArray& other) const noexcept
{
return ! operator== (other);
}
void StringArray::swapWith (StringArray& other) noexcept
{
strings.swapWith (other.strings);
}
void StringArray::clear()
{
strings.clear();
}
void StringArray::clearQuick()
{
strings.clearQuick();
}
const String& StringArray::operator[] (const int index) const noexcept
{
if (isPositiveAndBelow (index, strings.size()))
return strings.getReference (index);
return String::empty;
}
String& StringArray::getReference (const int index) noexcept
{
return strings.getReference (index);
}
void StringArray::add (const String& newString)
{
strings.add (newString);
}
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
void StringArray::add (String&& stringToAdd)
{
strings.add (static_cast<String&&> (stringToAdd));
}
#endif
void StringArray::insert (const int index, const String& newString)
{
strings.insert (index, newString);
}
void StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase)
{
if (! contains (newString, ignoreCase))
add (newString);
}
void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd)
{
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > otherArray.size())
numElementsToAdd = otherArray.size() - startIndex;
while (--numElementsToAdd >= 0)
strings.add (otherArray.strings.getReference (startIndex++));
}
void StringArray::set (const int index, const String& newString)
{
strings.set (index, newString);
}
bool StringArray::contains (StringRef stringToLookFor, const bool ignoreCase) const
{
return indexOf (stringToLookFor, ignoreCase) >= 0;
}
int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int i) const
{
if (i < 0)
i = 0;
const int numElements = size();
if (ignoreCase)
{
for (; i < numElements; ++i)
if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
return i;
}
else
{
for (; i < numElements; ++i)
if (stringToLookFor == strings.getReference (i))
return i;
}
return -1;
}
void StringArray::move (const int currentIndex, const int newIndex) noexcept
{
strings.move (currentIndex, newIndex);
}
//==============================================================================
void StringArray::remove (const int index)
{
strings.remove (index);
}
void StringArray::removeString (StringRef stringToRemove, const bool ignoreCase)
{
if (ignoreCase)
{
for (int i = size(); --i >= 0;)
if (strings.getReference(i).equalsIgnoreCase (stringToRemove))
strings.remove (i);
}
else
{
for (int i = size(); --i >= 0;)
if (stringToRemove == strings.getReference (i))
strings.remove (i);
}
}
void StringArray::removeRange (int startIndex, int numberToRemove)
{
strings.removeRange (startIndex, numberToRemove);
}
//==============================================================================
void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings)
{
if (removeWhitespaceStrings)
{
for (int i = size(); --i >= 0;)
if (! strings.getReference(i).containsNonWhitespaceChars())
strings.remove (i);
}
else
{
for (int i = size(); --i >= 0;)
if (strings.getReference(i).isEmpty())
strings.remove (i);
}
}
void StringArray::trim()
{
for (int i = size(); --i >= 0;)
{
String& s = strings.getReference(i);
s = s.trim();
}
}
//==============================================================================
struct InternalStringArrayComparator_CaseSensitive
{
static int compareElements (String& s1, String& s2) noexcept { return s1.compare (s2); }
};
struct InternalStringArrayComparator_CaseInsensitive
{
static int compareElements (String& s1, String& s2) noexcept { return s1.compareIgnoreCase (s2); }
};
struct InternalStringArrayComparator_Natural
{
static int compareElements (String& s1, String& s2) noexcept { return s1.compareNatural (s2); }
};
void StringArray::sort (const bool ignoreCase)
{
if (ignoreCase)
{
InternalStringArrayComparator_CaseInsensitive comp;
strings.sort (comp);
}
else
{
InternalStringArrayComparator_CaseSensitive comp;
strings.sort (comp);
}
}
void StringArray::sortNatural()
{
InternalStringArrayComparator_Natural comp;
strings.sort (comp);
}
//==============================================================================
String StringArray::joinIntoString (StringRef separator, int start, int numberToJoin) const
{
const int last = (numberToJoin < 0) ? size()
: jmin (size(), start + numberToJoin);
if (start < 0)
start = 0;
if (start >= last)
return String();
if (start == last - 1)
return strings.getReference (start);
const size_t separatorBytes = separator.text.sizeInBytes() - sizeof (String::CharPointerType::CharType);
size_t bytesNeeded = separatorBytes * (size_t) (last - start - 1);
for (int i = start; i < last; ++i)
bytesNeeded += strings.getReference(i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
String result;
result.preallocateBytes (bytesNeeded);
String::CharPointerType dest (result.getCharPointer());
while (start < last)
{
const String& s = strings.getReference (start);
if (! s.isEmpty())
dest.writeAll (s.getCharPointer());
if (++start < last && separatorBytes > 0)
dest.writeAll (separator.text);
}
dest.writeNull();
return result;
}
int StringArray::addTokens (StringRef text, const bool preserveQuotedStrings)
{
return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : "");
}
int StringArray::addTokens (StringRef text, StringRef breakCharacters, StringRef quoteCharacters)
{
int num = 0;
if (text.isNotEmpty())
{
for (String::CharPointerType t (text.text);;)
{
String::CharPointerType tokenEnd (CharacterFunctions::findEndOfToken (t,
breakCharacters.text,
quoteCharacters.text));
strings.add (String (t, tokenEnd));
++num;
if (tokenEnd.isEmpty())
break;
t = ++tokenEnd;
}
}
return num;
}
int StringArray::addLines (StringRef sourceText)
{
int numLines = 0;
String::CharPointerType text (sourceText.text);
bool finished = text.isEmpty();
while (! finished)
{
for (String::CharPointerType startOfLine (text);;)
{
const String::CharPointerType endOfLine (text);
switch (text.getAndAdvance())
{
case 0: finished = true; break;
case '\n': break;
case '\r': if (*text == '\n') ++text; break;
default: continue;
}
strings.add (String (startOfLine, endOfLine));
++numLines;
break;
}
}
return numLines;
}
StringArray StringArray::fromTokens (StringRef stringToTokenise, bool preserveQuotedStrings)
{
StringArray s;
s.addTokens (stringToTokenise, preserveQuotedStrings);
return s;
}
StringArray StringArray::fromTokens (StringRef stringToTokenise,
StringRef breakCharacters,
StringRef quoteCharacters)
{
StringArray s;
s.addTokens (stringToTokenise, breakCharacters, quoteCharacters);
return s;
}
StringArray StringArray::fromLines (StringRef stringToBreakUp)
{
StringArray s;
s.addLines (stringToBreakUp);
return s;
}
//==============================================================================
void StringArray::removeDuplicates (const bool ignoreCase)
{
for (int i = 0; i < size() - 1; ++i)
{
const String s (strings.getReference(i));
for (int nextIndex = i + 1;;)
{
nextIndex = indexOf (s, ignoreCase, nextIndex);
if (nextIndex < 0)
break;
strings.remove (nextIndex);
}
}
}
void StringArray::appendNumbersToDuplicates (const bool ignoreCase,
const bool appendNumberToFirstInstance,
CharPointer_UTF8 preNumberString,
CharPointer_UTF8 postNumberString)
{
CharPointer_UTF8 defaultPre (" ("), defaultPost (")");
if (preNumberString.getAddress() == nullptr)
preNumberString = defaultPre;
if (postNumberString.getAddress() == nullptr)
postNumberString = defaultPost;
for (int i = 0; i < size() - 1; ++i)
{
String& s = strings.getReference(i);
int nextIndex = indexOf (s, ignoreCase, i + 1);
if (nextIndex >= 0)
{
const String original (s);
int number = 0;
if (appendNumberToFirstInstance)
s = original + String (preNumberString) + String (++number) + String (postNumberString);
else
++number;
while (nextIndex >= 0)
{
set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString));
nextIndex = indexOf (original, ignoreCase, nextIndex + 1);
}
}
}
}
void StringArray::ensureStorageAllocated (int minNumElements)
{
strings.ensureStorageAllocated (minNumElements);
}
void StringArray::minimiseStorageOverheads()
{
strings.minimiseStorageOverheads();
}
@@ -0,0 +1,421 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_STRINGARRAY_H_INCLUDED
#define JUCE_STRINGARRAY_H_INCLUDED
//==============================================================================
/**
A special array for holding a list of strings.
@see String, StringPairArray
*/
class JUCE_API StringArray
{
public:
//==============================================================================
/** Creates an empty string array */
StringArray() noexcept;
/** Creates a copy of another string array */
StringArray (const StringArray&);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray (StringArray&&) noexcept;
#endif
/** Creates an array containing a single string. */
explicit StringArray (const String& firstValue);
/** Creates an array from a raw array of strings.
@param strings an array of strings to add
@param numberOfStrings how many items there are in the array
*/
StringArray (const String* strings, int numberOfStrings);
/** Creates a copy of an array of string literals.
@param strings an array of strings to add. Null pointers in the array will be
treated as empty strings
@param numberOfStrings how many items there are in the array
*/
StringArray (const char* const* strings, int numberOfStrings);
/** Creates a copy of a null-terminated array of string literals.
Each item from the array passed-in is added, until it encounters a null pointer,
at which point it stops.
*/
explicit StringArray (const char* const* strings);
/** Creates a copy of a null-terminated array of string literals.
Each item from the array passed-in is added, until it encounters a null pointer,
at which point it stops.
*/
explicit StringArray (const wchar_t* const* strings);
/** Creates a copy of an array of string literals.
@param strings an array of strings to add. Null pointers in the array will be
treated as empty strings
@param numberOfStrings how many items there are in the array
*/
StringArray (const wchar_t* const* strings, int numberOfStrings);
/** Destructor. */
~StringArray();
/** Copies the contents of another string array into this one */
StringArray& operator= (const StringArray&);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray& operator= (StringArray&&) noexcept;
#endif
/** Swaps the contents of this and another StringArray. */
void swapWith (StringArray&) noexcept;
//==============================================================================
/** Compares two arrays.
Comparisons are case-sensitive.
@returns true only if the other array contains exactly the same strings in the same order
*/
bool operator== (const StringArray&) const noexcept;
/** Compares two arrays.
Comparisons are case-sensitive.
@returns false if the other array contains exactly the same strings in the same order
*/
bool operator!= (const StringArray&) const noexcept;
//==============================================================================
/** Returns the number of strings in the array */
inline int size() const noexcept { return strings.size(); };
/** Returns one of the strings from the array.
If the index is out-of-range, an empty string is returned.
Obviously the reference returned shouldn't be stored for later use, as the
string it refers to may disappear when the array changes.
*/
const String& operator[] (int index) const noexcept;
/** Returns a reference to one of the strings in the array.
This lets you modify a string in-place in the array, but you must be sure that
the index is in-range.
*/
String& getReference (int index) noexcept;
/** Returns a pointer to the first String in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline String* begin() const noexcept { return strings.begin(); }
/** Returns a pointer to the String which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline String* end() const noexcept { return strings.end(); }
/** Searches for a string in the array.
The comparison will be case-insensitive if the ignoreCase parameter is true.
@returns true if the string is found inside the array
*/
bool contains (StringRef stringToLookFor,
bool ignoreCase = false) const;
/** Searches for a string in the array.
The comparison will be case-insensitive if the ignoreCase parameter is true.
@param stringToLookFor the string to try to find
@param ignoreCase whether the comparison should be case-insensitive
@param startIndex the first index to start searching from
@returns the index of the first occurrence of the string in this array,
or -1 if it isn't found.
*/
int indexOf (StringRef stringToLookFor,
bool ignoreCase = false,
int startIndex = 0) const;
//==============================================================================
/** Appends a string at the end of the array. */
void add (const String& stringToAdd);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
/** Appends a string at the end of the array. */
void add (String&& stringToAdd);
#endif
/** Inserts a string into the array.
This will insert a string into the array at the given index, moving
up the other elements to make room for it.
If the index is less than zero or greater than the size of the array,
the new string will be added to the end of the array.
*/
void insert (int index, const String& stringToAdd);
/** Adds a string to the array as long as it's not already in there.
The search can optionally be case-insensitive.
*/
void addIfNotAlreadyThere (const String& stringToAdd, bool ignoreCase = false);
/** Replaces one of the strings in the array with another one.
If the index is higher than the array's size, the new string will be
added to the end of the array; if it's less than zero nothing happens.
*/
void set (int index, const String& newString);
/** Appends some strings from another array to the end of this one.
@param other the array to add
@param startIndex the first element of the other array to add
@param numElementsToAdd the maximum number of elements to add (if this is
less than zero, they are all added)
*/
void addArray (const StringArray& other,
int startIndex = 0,
int numElementsToAdd = -1);
/** Breaks up a string into tokens and adds them to this array.
This will tokenise the given string using whitespace characters as the
token delimiters, and will add these tokens to the end of the array.
@returns the number of tokens added
@see fromTokens
*/
int addTokens (StringRef stringToTokenise, bool preserveQuotedStrings);
/** Breaks up a string into tokens and adds them to this array.
This will tokenise the given string (using the string passed in to define the
token delimiters), and will add these tokens to the end of the array.
@param stringToTokenise the string to tokenise
@param breakCharacters a string of characters, any of which will be considered
to be a token delimiter.
@param quoteCharacters if this string isn't empty, it defines a set of characters
which are treated as quotes. Any text occurring
between quotes is not broken up into tokens.
@returns the number of tokens added
@see fromTokens
*/
int addTokens (StringRef stringToTokenise,
StringRef breakCharacters,
StringRef quoteCharacters);
/** Breaks up a string into lines and adds them to this array.
This breaks a string down into lines separated by \\n or \\r\\n, and adds each line
to the array. Line-break characters are omitted from the strings that are added to
the array.
*/
int addLines (StringRef stringToBreakUp);
/** Returns an array containing the tokens in a given string.
This will tokenise the given string using whitespace characters as the
token delimiters, and return these tokens as an array.
@see addTokens
*/
static StringArray fromTokens (StringRef stringToTokenise,
bool preserveQuotedStrings);
/** Returns an array containing the tokens in a given string.
This will tokenise the given string using whitespace characters as the
token delimiters, and return these tokens as an array.
@param stringToTokenise the string to tokenise
@param breakCharacters a string of characters, any of which will be considered
to be a token delimiter.
@param quoteCharacters if this string isn't empty, it defines a set of characters
which are treated as quotes. Any text occurring
between quotes is not broken up into tokens.
@see addTokens
*/
static StringArray fromTokens (StringRef stringToTokenise,
StringRef breakCharacters,
StringRef quoteCharacters);
/** Returns an array containing the lines in a given string.
This breaks a string down into lines separated by \\n or \\r\\n, and returns an
array containing these lines. Line-break characters are omitted from the strings that
are added to the array.
*/
static StringArray fromLines (StringRef stringToBreakUp);
//==============================================================================
/** Removes all elements from the array. */
void clear();
/** Removes all elements from the array without freeing the array's allocated storage.
@see clear
*/
void clearQuick();
/** Removes a string from the array.
If the index is out-of-range, no action will be taken.
*/
void remove (int index);
/** Finds a string in the array and removes it.
This will remove the first occurrence of the given string from the array. The
comparison may be case-insensitive depending on the ignoreCase parameter.
*/
void removeString (StringRef stringToRemove,
bool ignoreCase = false);
/** Removes a range of elements from the array.
This will remove a set of elements, starting from the given index,
and move subsequent elements down to close the gap.
If the range extends beyond the bounds of the array, it will
be safely clipped to the size of the array.
@param startIndex the index of the first element to remove
@param numberToRemove how many elements should be removed
*/
void removeRange (int startIndex, int numberToRemove);
/** Removes any duplicated elements from the array.
If any string appears in the array more than once, only the first occurrence of
it will be retained.
@param ignoreCase whether to use a case-insensitive comparison
*/
void removeDuplicates (bool ignoreCase);
/** Removes empty strings from the array.
@param removeWhitespaceStrings if true, strings that only contain whitespace
characters will also be removed
*/
void removeEmptyStrings (bool removeWhitespaceStrings = true);
/** Moves one of the strings to a different position.
This will move the string to a specified index, shuffling along
any intervening elements as required.
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
@param currentIndex the index of the value to be moved. If this isn't a
valid index, then nothing will be done
@param newIndex the index at which you'd like this value to end up. If this
is less than zero, the value will be moved to the end
of the array
*/
void move (int currentIndex, int newIndex) noexcept;
/** Deletes any whitespace characters from the starts and ends of all the strings. */
void trim();
/** Adds numbers to the strings in the array, to make each string unique.
This will add numbers to the ends of groups of similar strings.
e.g. if there are two "moose" strings, they will become "moose (1)" and "moose (2)"
@param ignoreCaseWhenComparing whether the comparison used is case-insensitive
@param appendNumberToFirstInstance whether the first of a group of similar strings
also has a number appended to it.
@param preNumberString when adding a number, this string is added before the number.
If you pass 0, a default string will be used, which adds
brackets around the number.
@param postNumberString this string is appended after any numbers that are added.
If you pass 0, a default string will be used, which adds
brackets around the number.
*/
void appendNumbersToDuplicates (bool ignoreCaseWhenComparing,
bool appendNumberToFirstInstance,
CharPointer_UTF8 preNumberString = CharPointer_UTF8 (nullptr),
CharPointer_UTF8 postNumberString = CharPointer_UTF8 (nullptr));
//==============================================================================
/** Joins the strings in the array together into one string.
This will join a range of elements from the array into a string, separating
them with a given string.
e.g. joinIntoString (",") will turn an array of "a" "b" and "c" into "a,b,c".
@param separatorString the string to insert between all the strings
@param startIndex the first element to join
@param numberOfElements how many elements to join together. If this is less
than zero, all available elements will be used.
*/
String joinIntoString (StringRef separatorString,
int startIndex = 0,
int numberOfElements = -1) const;
//==============================================================================
/** Sorts the array into alphabetical order.
@param ignoreCase if true, the comparisons used will be case-sensitive.
*/
void sort (bool ignoreCase);
/** Sorts the array using extra language-aware rules to do a better job of comparing
words containing spaces and numbers.
@see String::compareNatural()
*/
void sortNatural();
//==============================================================================
/** Increases the array's internal storage to hold a minimum number of elements.
Calling this before adding a large known number of elements means that
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated (int minNumElements);
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads();
/** This is the array holding the actual strings. This is public to allow direct access
to array methods that may not already be provided by the StringArray class.
*/
Array<String> strings;
private:
JUCE_LEAK_DETECTOR (StringArray)
};
#endif // JUCE_STRINGARRAY_H_INCLUDED
@@ -0,0 +1,147 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
StringPairArray::StringPairArray (const bool ignoreCase_)
: ignoreCase (ignoreCase_)
{
}
StringPairArray::StringPairArray (const StringPairArray& other)
: keys (other.keys),
values (other.values),
ignoreCase (other.ignoreCase)
{
}
StringPairArray::~StringPairArray()
{
}
StringPairArray& StringPairArray::operator= (const StringPairArray& other)
{
keys = other.keys;
values = other.values;
return *this;
}
bool StringPairArray::operator== (const StringPairArray& other) const
{
for (int i = keys.size(); --i >= 0;)
if (other [keys[i]] != values[i])
return false;
return true;
}
bool StringPairArray::operator!= (const StringPairArray& other) const
{
return ! operator== (other);
}
const String& StringPairArray::operator[] (StringRef key) const
{
return values [keys.indexOf (key, ignoreCase)];
}
String StringPairArray::getValue (StringRef key, const String& defaultReturnValue) const
{
const int i = keys.indexOf (key, ignoreCase);
if (i >= 0)
return values[i];
return defaultReturnValue;
}
bool StringPairArray::containsKey (StringRef key) const noexcept
{
return keys.contains (key);
}
void StringPairArray::set (const String& key, const String& value)
{
const int i = keys.indexOf (key, ignoreCase);
if (i >= 0)
{
values.set (i, value);
}
else
{
keys.add (key);
values.add (value);
}
}
void StringPairArray::addArray (const StringPairArray& other)
{
for (int i = 0; i < other.size(); ++i)
set (other.keys[i], other.values[i]);
}
void StringPairArray::clear()
{
keys.clear();
values.clear();
}
void StringPairArray::remove (StringRef key)
{
remove (keys.indexOf (key, ignoreCase));
}
void StringPairArray::remove (const int index)
{
keys.remove (index);
values.remove (index);
}
void StringPairArray::setIgnoresCase (const bool shouldIgnoreCase)
{
ignoreCase = shouldIgnoreCase;
}
String StringPairArray::getDescription() const
{
String s;
for (int i = 0; i < keys.size(); ++i)
{
s << keys[i] << " = " << values[i];
if (i < keys.size())
s << ", ";
}
return s;
}
void StringPairArray::minimiseStorageOverheads()
{
keys.minimiseStorageOverheads();
values.minimiseStorageOverheads();
}
@@ -0,0 +1,157 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_STRINGPAIRARRAY_H_INCLUDED
#define JUCE_STRINGPAIRARRAY_H_INCLUDED
//==============================================================================
/**
A container for holding a set of strings which are keyed by another string.
@see StringArray
*/
class JUCE_API StringPairArray
{
public:
//==============================================================================
/** Creates an empty array */
StringPairArray (bool ignoreCaseWhenComparingKeys = true);
/** Creates a copy of another array */
StringPairArray (const StringPairArray& other);
/** Destructor. */
~StringPairArray();
/** Copies the contents of another string array into this one */
StringPairArray& operator= (const StringPairArray& other);
//==============================================================================
/** Compares two arrays.
Comparisons are case-sensitive.
@returns true only if the other array contains exactly the same strings with the same keys
*/
bool operator== (const StringPairArray& other) const;
/** Compares two arrays.
Comparisons are case-sensitive.
@returns false if the other array contains exactly the same strings with the same keys
*/
bool operator!= (const StringPairArray& other) const;
//==============================================================================
/** Finds the value corresponding to a key string.
If no such key is found, this will just return an empty string. To check whether
a given key actually exists (because it might actually be paired with an empty string), use
the getAllKeys() method to obtain a list.
Obviously the reference returned shouldn't be stored for later use, as the
string it refers to may disappear when the array changes.
@see getValue
*/
const String& operator[] (StringRef key) const;
/** Finds the value corresponding to a key string.
If no such key is found, this will just return the value provided as a default.
@see operator[]
*/
String getValue (StringRef, const String& defaultReturnValue) const;
/** Returns true if the given key exists. */
bool containsKey (StringRef key) const noexcept;
/** Returns a list of all keys in the array. */
const StringArray& getAllKeys() const noexcept { return keys; }
/** Returns a list of all values in the array. */
const StringArray& getAllValues() const noexcept { return values; }
/** Returns the number of strings in the array */
inline int size() const noexcept { return keys.size(); };
//==============================================================================
/** Adds or amends a key/value pair.
If a value already exists with this key, its value will be overwritten,
otherwise the key/value pair will be added to the array.
*/
void set (const String& key, const String& value);
/** Adds the items from another array to this one.
This is equivalent to using set() to add each of the pairs from the other array.
*/
void addArray (const StringPairArray& other);
//==============================================================================
/** Removes all elements from the array. */
void clear();
/** Removes a string from the array based on its key.
If the key isn't found, nothing will happen.
*/
void remove (StringRef key);
/** Removes a string from the array based on its index.
If the index is out-of-range, no action will be taken.
*/
void remove (int index);
//==============================================================================
/** Indicates whether to use a case-insensitive search when looking up a key string.
*/
void setIgnoresCase (bool shouldIgnoreCase);
//==============================================================================
/** Returns a descriptive string containing the items.
This is handy for dumping the contents of an array.
*/
String getDescription() const;
//==============================================================================
/** Reduces the amount of storage being used by the array.
Arrays typically allocate slightly more storage than they need, and after
removing elements, they may have quite a lot of unused space allocated.
This method will reduce the amount of allocated storage to a minimum.
*/
void minimiseStorageOverheads();
private:
//==============================================================================
StringArray keys, values;
bool ignoreCase;
JUCE_LEAK_DETECTOR (StringPairArray)
};
#endif // JUCE_STRINGPAIRARRAY_H_INCLUDED
@@ -0,0 +1,166 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
static const int minNumberOfStringsForGarbageCollection = 300;
static const uint32 garbageCollectionInterval = 30000;
StringPool::StringPool() noexcept : lastGarbageCollectionTime (0) {}
StringPool::~StringPool() {}
struct StartEndString
{
StartEndString (String::CharPointerType s, String::CharPointerType e) noexcept : start (s), end (e) {}
operator String() const { return String (start, end); }
String::CharPointerType start, end;
};
static int compareStrings (const String& s1, const String& s2) noexcept { return s1.compare (s2); }
static int compareStrings (CharPointer_UTF8 s1, const String& s2) noexcept { return s1.compare (s2.getCharPointer()); }
static int compareStrings (const StartEndString& string1, const String& string2) noexcept
{
String::CharPointerType s1 (string1.start), s2 (string2.getCharPointer());
for (;;)
{
const int c1 = s1 < string1.end ? (int) s1.getAndAdvance() : 0;
const int c2 = (int) s2.getAndAdvance();
const int diff = c1 - c2;
if (diff != 0) return diff < 0 ? -1 : 1;
if (c1 == 0) break;
}
return 0;
}
template <typename NewStringType>
static String addPooledString (Array<String>& strings, const NewStringType& newString)
{
int start = 0;
int end = strings.size();
while (start < end)
{
const String& startString = strings.getReference (start);
const int startComp = compareStrings (newString, startString);
if (startComp == 0)
return startString;
const int halfway = (start + end) / 2;
if (halfway == start)
{
if (startComp > 0)
++start;
break;
}
const String& halfwayString = strings.getReference (halfway);
const int halfwayComp = compareStrings (newString, halfwayString);
if (halfwayComp == 0)
return halfwayString;
if (halfwayComp > 0)
start = halfway;
else
end = halfway;
}
strings.insert (start, newString);
return strings.getReference (start);
}
String StringPool::getPooledString (const char* const newString)
{
if (newString == nullptr || *newString == 0)
return String();
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, CharPointer_UTF8 (newString));
}
String StringPool::getPooledString (String::CharPointerType start, String::CharPointerType end)
{
if (start.isEmpty() || start == end)
return String();
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, StartEndString (start, end));
}
String StringPool::getPooledString (StringRef newString)
{
if (newString.isEmpty())
return String();
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, newString.text);
}
String StringPool::getPooledString (const String& newString)
{
if (newString.isEmpty())
return String();
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, newString);
}
void StringPool::garbageCollectIfNeeded()
{
if (strings.size() > minNumberOfStringsForGarbageCollection
&& Time::getApproximateMillisecondCounter() > lastGarbageCollectionTime + garbageCollectionInterval)
garbageCollect();
}
void StringPool::garbageCollect()
{
const ScopedLock sl (lock);
for (int i = strings.size(); --i >= 0;)
if (strings.getReference(i).getReferenceCount() == 1)
strings.remove (i);
lastGarbageCollectionTime = Time::getApproximateMillisecondCounter();
}
StringPool& StringPool::getGlobalPool() noexcept
{
static StringPool pool;
return pool;
}
@@ -0,0 +1,94 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_STRINGPOOL_H_INCLUDED
#define JUCE_STRINGPOOL_H_INCLUDED
//==============================================================================
/**
A StringPool holds a set of shared strings, which reduces storage overheads and improves
comparison speed when dealing with many duplicate strings.
When you add a string to a pool using getPooledString, it'll return a character
array containing the same string. This array is owned by the pool, and the same array
is returned every time a matching string is asked for. This means that it's trivial to
compare two pooled strings for equality, as you can simply compare their pointers. It
also cuts down on storage if you're using many copies of the same string.
*/
class JUCE_API StringPool
{
public:
//==============================================================================
/** Creates an empty pool. */
StringPool() noexcept;
/** Destructor */
~StringPool();
//==============================================================================
/** Returns a pointer to a shared copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString (const String& original);
/** Returns a pointer to a copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString (const char* original);
/** Returns a pointer to a shared copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString (StringRef original);
/** Returns a pointer to a copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString (String::CharPointerType start, String::CharPointerType end);
//==============================================================================
/** Scans the pool, and removes any strings that are unreferenced.
You don't generally need to call this - it'll be called automatically when the pool grows
large enough to warrant it.
*/
void garbageCollect();
/** Returns a shared global pool which is used for things like Identifiers, XML parsing. */
static StringPool& getGlobalPool() noexcept;
private:
Array<String> strings;
CriticalSection lock;
uint32 lastGarbageCollectionTime;
void garbageCollectIfNeeded();
};
#endif // JUCE_STRINGPOOL_H_INCLUDED
@@ -0,0 +1,138 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_STRINGREF_H_INCLUDED
#define JUCE_STRINGREF_H_INCLUDED
//==============================================================================
/**
A simple class for holding temporary references to a string literal or String.
Unlike a real String object, the StringRef does not allocate any memory or
take ownership of the strings you give to it - it simply holds a reference to
a string that has been allocated elsewhere.
The main purpose of the class is to be used instead of a const String& as the type
of function arguments where the caller may pass either a string literal or a String
object. This means that when the called uses a string literal, there's no need
for an temporary String object to be allocated, and this cuts down overheads
substantially.
Because the class is simply a wrapper around a pointer, you should always pass
it by value, not by reference.
@code
void myStringFunction1 (const String&);
void myStringFunction2 (StringRef);
myStringFunction1 ("abc"); // Implicitly allocates a temporary String object.
myStringFunction2 ("abc"); // Much faster, as no local allocations are needed.
@endcode
For examples of it in use, see the XmlElement or StringArray classes.
Bear in mind that there are still many cases where it's better to use an argument
which is a const String&. For example if the function stores the string or needs
to internally create a String from the argument, then it's better for the original
argument to already be a String.
@see String
*/
class JUCE_API StringRef
{
public:
/** Creates a StringRef from a raw string literal.
The StringRef object does NOT take ownership or copy this data, so you must
ensure that the data does not change during the lifetime of the StringRef.
Note that this pointer not be null!
*/
StringRef (const char* stringLiteral) noexcept;
/** Creates a StringRef from a raw char pointer.
The StringRef object does NOT take ownership or copy this data, so you must
ensure that the data does not change during the lifetime of the StringRef.
*/
StringRef (String::CharPointerType stringLiteral) noexcept;
/** Creates a StringRef from a String.
The StringRef object does NOT take ownership or copy the data from the String,
so you must ensure that the String is not modified or deleted during the lifetime
of the StringRef.
*/
StringRef (const String& string) noexcept;
/** Creates a StringRef pointer to an empty string. */
StringRef() noexcept;
//==============================================================================
/** Returns a raw pointer to the underlying string data. */
operator const String::CharPointerType::CharType*() const noexcept { return text.getAddress(); }
/** Returns a pointer to the underlying string data as a char pointer object. */
operator String::CharPointerType() const noexcept { return text; }
/** Returns true if the string is empty. */
bool isEmpty() const noexcept { return text.isEmpty(); }
/** Returns true if the string is not empty. */
bool isNotEmpty() const noexcept { return ! text.isEmpty(); }
/** Returns the number of characters in the string. */
int length() const noexcept { return (int) text.length(); }
/** Retrieves a character by index. */
juce_wchar operator[] (int index) const noexcept { return text[index]; }
/** Compares this StringRef with a String. */
bool operator== (const String& s) const noexcept { return text.compare (s.getCharPointer()) == 0; }
/** Compares this StringRef with a String. */
bool operator!= (const String& s) const noexcept { return text.compare (s.getCharPointer()) != 0; }
/** Case-sensitive comparison of two StringRefs. */
bool operator== (StringRef s) const noexcept { return text.compare (s.text) == 0; }
/** Case-sensitive comparison of two StringRefs. */
bool operator!= (StringRef s) const noexcept { return text.compare (s.text) != 0; }
//==============================================================================
/** The text that is referenced. */
String::CharPointerType text;
#if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN)
// Sorry, non-UTF8 people, you're unable to take advantage of StringRef, because
// you've chosen a character encoding that doesn't match C++ string literals.
String stringCopy;
#endif
};
//==============================================================================
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, StringRef string2) noexcept;
/** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, StringRef string2) noexcept;
#if JUCE_STRING_UTF_TYPE != 8 && ! defined (DOXYGEN)
inline String operator+ (String s1, StringRef s2) { return s1 += String (s2.text); }
#endif
#endif // JUCE_STRINGREF_H_INCLUDED
@@ -0,0 +1,247 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
struct TextDiffHelpers
{
enum { minLengthToMatch = 3 };
struct StringRegion
{
StringRegion (const String& s) noexcept
: text (s.getCharPointer()), start (0), length (s.length()) {}
StringRegion (const String::CharPointerType t, int s, int len) noexcept
: text (t), start (s), length (len) {}
String::CharPointerType text;
int start, length;
};
static void addInsertion (TextDiff& td, const String::CharPointerType text, int index, int length)
{
TextDiff::Change c;
c.insertedText = String (text, (size_t) length);
c.start = index;
c.length = length;
td.changes.add (c);
}
static void addDeletion (TextDiff& td, int index, int length)
{
TextDiff::Change c;
c.start = index;
c.length = length;
td.changes.add (c);
}
static void diffSkippingCommonStart (TextDiff& td, const StringRegion& a, const StringRegion& b)
{
String::CharPointerType sa (a.text);
String::CharPointerType sb (b.text);
const int maxLen = jmax (a.length, b.length);
for (int i = 0; i < maxLen; ++i, ++sa, ++sb)
{
if (*sa != *sb)
{
diffRecursively (td, StringRegion (sa, a.start + i, a.length - i),
StringRegion (sb, b.start + i, b.length - i));
break;
}
}
}
static void diffRecursively (TextDiff& td, const StringRegion& a, const StringRegion& b)
{
int indexA, indexB;
const int len = findLongestCommonSubstring (a.text, a.length,
b.text, b.length,
indexA, indexB);
if (len >= minLengthToMatch)
{
if (indexA > 0 && indexB > 0)
diffSkippingCommonStart (td, StringRegion (a.text, a.start, indexA),
StringRegion (b.text, b.start, indexB));
else if (indexA > 0)
addDeletion (td, b.start, indexA);
else if (indexB > 0)
addInsertion (td, b.text, b.start, indexB);
diffRecursively (td, StringRegion (a.text + indexA + len, a.start + indexA + len, a.length - indexA - len),
StringRegion (b.text + indexB + len, b.start + indexB + len, b.length - indexB - len));
}
else
{
if (a.length > 0) addDeletion (td, b.start, a.length);
if (b.length > 0) addInsertion (td, b.text, b.start, b.length);
}
}
static int findLongestCommonSubstring (String::CharPointerType a, const int lenA,
const String::CharPointerType b, const int lenB,
int& indexInA, int& indexInB)
{
if (lenA == 0 || lenB == 0)
return 0;
HeapBlock<int> lines;
lines.calloc (2 + 2 * (size_t) lenB);
int* l0 = lines;
int* l1 = l0 + lenB + 1;
int loopsWithoutImprovement = 0;
int bestLength = 0;
indexInA = indexInB = 0;
for (int i = 0; i < lenA; ++i)
{
const juce_wchar ca = a.getAndAdvance();
String::CharPointerType b2 (b);
for (int j = 0; j < lenB; ++j)
{
if (ca != b2.getAndAdvance())
{
l1[j + 1] = 0;
}
else
{
const int len = l0[j] + 1;
l1[j + 1] = len;
if (len > bestLength)
{
loopsWithoutImprovement = 0;
bestLength = len;
indexInA = i;
indexInB = j;
}
}
}
if (++loopsWithoutImprovement > 100)
break;
std::swap (l0, l1);
}
indexInA -= bestLength - 1;
indexInB -= bestLength - 1;
return bestLength;
}
};
TextDiff::TextDiff (const String& original, const String& target)
{
TextDiffHelpers::diffSkippingCommonStart (*this, original, target);
}
String TextDiff::appliedTo (String text) const
{
for (int i = 0; i < changes.size(); ++i)
text = changes.getReference(i).appliedTo (text);
return text;
}
bool TextDiff::Change::isDeletion() const noexcept
{
return insertedText.isEmpty();
}
String TextDiff::Change::appliedTo (const String& text) const noexcept
{
return text.substring (0, start) + (isDeletion() ? text.substring (start + length)
: (insertedText + text.substring (start)));
}
//==============================================================================
//==============================================================================
#if JUCE_UNIT_TESTS
class DiffTests : public UnitTest
{
public:
DiffTests() : UnitTest ("TextDiff class") {}
static String createString (Random& r)
{
juce_wchar buffer[50] = { 0 };
for (int i = r.nextInt (49); --i >= 0;)
{
if (r.nextInt (10) == 0)
{
do
{
buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
}
while (! CharPointer_UTF16::canRepresent (buffer[i]));
}
else
buffer[i] = (juce_wchar) ('a' + r.nextInt (3));
}
return CharPointer_UTF32 (buffer);
}
void testDiff (const String& a, const String& b)
{
TextDiff diff (a, b);
const String result (diff.appliedTo (a));
expectEquals (result, b);
}
void runTest()
{
beginTest ("TextDiff");
Random r = getRandom();
testDiff (String::empty, String::empty);
testDiff ("x", String::empty);
testDiff (String::empty, "x");
testDiff ("x", "x");
testDiff ("x", "y");
testDiff ("xxx", "x");
testDiff ("x", "xxx");
for (int i = 5000; --i >= 0;)
{
String s (createString (r));
testDiff (s, createString (r));
testDiff (s + createString (r), s + createString (r));
}
}
};
static DiffTests diffTests;
#endif
@@ -0,0 +1,80 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission to use, copy, modify, and/or distribute this software for any purpose with
or without fee is hereby granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_TEXTDIFF_H_INCLUDED
#define JUCE_TEXTDIFF_H_INCLUDED
/**
Calculates and applies a sequence of changes to convert one text string into
another.
Once created, the TextDiff object contains an array of change objects, where
each change can be either an insertion or a deletion. When applied in order
to the original string, these changes will convert it to the target string.
*/
class JUCE_API TextDiff
{
public:
/** Creates a set of diffs for converting the original string into the target. */
TextDiff (const String& original,
const String& target);
/** Applies this sequence of changes to the original string, producing the
target string that was specified when generating them.
Obviously it only makes sense to call this function with the string that
was originally passed to the constructor. Any other input will produce an
undefined result.
*/
String appliedTo (String text) const;
/** Describes a change, which can be either an insertion or deletion. */
struct Change
{
String insertedText; /**< If this change is a deletion, this string will be empty; otherwise,
it'll be the text that should be inserted at the index specified by start. */
int start; /**< Specifies the character index in a string at which text should be inserted or deleted. */
int length; /**< If this change is a deletion, this specifies the number of characters to delete. For an
insertion, this is the length of the new text being inserted. */
/** Returns true if this change is a deletion, or false for an insertion. */
bool isDeletion() const noexcept;
/** Returns the result of applying this change to a string. */
String appliedTo (const String& original) const noexcept;
};
/** The list of changes required to perform the transformation.
Applying each of these, in order, to the original string will produce the target.
*/
Array<Change> changes;
};
#endif // JUCE_TEXTDIFF_H_INCLUDED