27#if JUCE_WINDOWS && ! defined (DOXYGEN)
28 #define JUCE_NATIVE_WCHAR_IS_UTF8 0
29 #define JUCE_NATIVE_WCHAR_IS_UTF16 1
30 #define JUCE_NATIVE_WCHAR_IS_UTF32 0
33 #define JUCE_NATIVE_WCHAR_IS_UTF8 0
35 #define JUCE_NATIVE_WCHAR_IS_UTF16 0
37 #define JUCE_NATIVE_WCHAR_IS_UTF32 1
40#if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
49 #define JUCE_T(stringLiteral) (L##stringLiteral)
52#if JUCE_DEFINE_T_MACRO
60 #define T(stringLiteral) JUCE_T(stringLiteral)
69 template <
typename Type>
struct make_unsigned {
using type = Type; };
70 template <>
struct make_unsigned<signed
char> {
using type =
unsigned char; };
71 template <>
struct make_unsigned<
char> {
using type =
unsigned char; };
72 template <>
struct make_unsigned<
short> {
using type =
unsigned short; };
73 template <>
struct make_unsigned<
int> {
using type =
unsigned int; };
74 template <>
struct make_unsigned<
long> {
using type =
unsigned long; };
75 template <>
struct make_unsigned<
long long> {
using type =
unsigned long long; };
101 static bool isUpperCase (
juce_wchar character)
noexcept;
103 static bool isLowerCase (
juce_wchar character)
noexcept;
106 static bool isWhitespace (
char character)
noexcept;
108 static bool isWhitespace (
juce_wchar character)
noexcept;
111 static bool isDigit (
char character)
noexcept;
113 static bool isDigit (
juce_wchar character)
noexcept;
116 static bool isLetter (
char character)
noexcept;
118 static bool isLetter (
juce_wchar character)
noexcept;
121 static bool isLetterOrDigit (
char character)
noexcept;
123 static bool isLetterOrDigit (
juce_wchar character)
noexcept;
128 static bool isPrintable (
char character)
noexcept;
133 static bool isPrintable (
juce_wchar character)
noexcept;
136 static int getHexDigitValue (
juce_wchar digit)
noexcept;
139 static juce_wchar getUnicodeCharFromWindows1252Codepage (
uint8 windows1252Char)
noexcept;
146 template <
typename CharPo
interType>
151 bool isNegative =
false;
153 constexpr const int maxSignificantDigits = 17 + 1;
154 constexpr const int bufferSize = maxSignificantDigits + 7 + 1;
155 char buffer[(
size_t) bufferSize] = {};
156 char* writePtr = &(buffer[0]);
159 const auto endOfWhitspace = text.findEndOfWhitespace();
160 text = endOfWhitspace;
184 if ((text[1] ==
'a' || text[1] ==
'A') && (text[2] ==
'n' || text[2] ==
'N'))
190 text = endOfWhitspace;
197 if ((text[1] ==
'n' || text[1] ==
'N') && (text[2] ==
'f' || text[2] ==
'F'))
200 return isNegative ? -inf : inf;
203 text = endOfWhitspace;
214 double result[3] = { 0 }, accumulator[2] = { 0 };
215 int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
216 int exponent = 0, decPointIndex = 0, digit = 0;
217 int lastDigit = 0, numSignificantDigits = 0;
218 bool digitsFound =
false;
219 constexpr const int maxSignificantDigits = 17 + 1;
226 digit = (
int) text.getAndAdvance() -
'0';
229 if (decPointIndex != 0)
230 exponentAdjustment[1]++;
232 if (numSignificantDigits == 0 && digit == 0)
235 if (++numSignificantDigits > maxSignificantDigits)
238 ++accumulator [decPointIndex];
239 else if (digit == 5 && (lastDigit & 1) != 0)
240 ++accumulator [decPointIndex];
242 if (decPointIndex > 0)
243 exponentAdjustment[1]--;
245 exponentAdjustment[0]++;
247 while (text.isDigit())
250 if (decPointIndex == 0)
251 exponentAdjustment[0]++;
257 if (accumulator [decPointIndex] > maxAccumulatorValue)
259 result [decPointIndex] = mulexp10 (result [decPointIndex], exponentAccumulator [decPointIndex])
260 + accumulator [decPointIndex];
261 accumulator [decPointIndex] = 0;
262 exponentAccumulator [decPointIndex] = 0;
265 accumulator [decPointIndex] = accumulator[decPointIndex] * 10 + digit;
266 exponentAccumulator [decPointIndex]++;
269 else if (decPointIndex == 0 && *text ==
'.')
274 if (numSignificantDigits > maxSignificantDigits)
276 while (text.isDigit())
287 result[0] = mulexp10 (result[0], exponentAccumulator[0]) + accumulator[0];
289 if (decPointIndex != 0)
290 result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1];
293 if ((c ==
'e' || c ==
'E') && digitsFound)
295 auto negativeExponent =
false;
303 while (text.isDigit())
304 exponent = (exponent * 10) + ((
int) text.getAndAdvance() -
'0');
306 if (negativeExponent)
307 exponent = -exponent;
310 auto r = mulexp10 (result[0], exponent + exponentAdjustment[0]);
311 if (decPointIndex != 0)
312 r += mulexp10 (result[1], exponent - exponentAdjustment[1]);
314 return isNegative ? -r : r;
318 int numSigFigs = 0, extraExponent = 0;
319 bool decimalPointFound =
false, leadingZeros =
false;
325 auto digit = (
int) text.getAndAdvance() -
'0';
327 if (decimalPointFound)
329 if (numSigFigs >= maxSignificantDigits)
334 if (numSigFigs >= maxSignificantDigits)
340 if (numSigFigs == 0 && digit == 0)
347 *writePtr++ = (
char) (
'0' + (
char) digit);
350 else if ((! decimalPointFound) && *text ==
'.')
354 decimalPointFound =
true;
362 if ((! leadingZeros) && (numSigFigs == 0))
364 text = endOfWhitspace;
368 auto writeExponentDigits = [] (
int exponent,
char* destination)
370 auto exponentDivisor = 100;
372 while (exponentDivisor > 1)
374 auto digit = exponent / exponentDivisor;
375 *destination++ = (
char) (
'0' + (
char) digit);
376 exponent -= digit * exponentDivisor;
377 exponentDivisor /= 10;
380 *destination++ = (
char) (
'0' + (
char) exponent);
385 if (c ==
'e' || c ==
'E')
387 const auto startOfExponent = text;
389 bool parsedExponentIsPositive =
true;
394 parsedExponentIsPositive =
false;
404 const auto startOfExponentDigits = text;
406 while (text.isDigit())
408 auto digit = (
int) text.getAndAdvance() -
'0';
410 if (digit != 0 || exponent != 0)
411 exponent = (exponent * 10) + digit;
414 if (text == startOfExponentDigits)
415 text = startOfExponent;
417 exponent = extraExponent + (parsedExponentIsPositive ? exponent : -exponent);
422 return isNegative ? -0.0 : 0.0;
425 exponent = -exponent;
429 return isNegative ? -inf : inf;
432 writeExponentDigits (exponent, writePtr);
434 else if (extraExponent > 0)
437 writeExponentDigits (extraExponent, writePtr);
441 static _locale_t locale = _create_locale (LC_ALL,
"C");
442 return _strtod_l (&buffer[0],
nullptr, locale);
444 static locale_t locale =
newlocale (LC_ALL_MASK,
"C",
nullptr);
446 return (
double) strtold_l (&buffer[0],
nullptr, locale);
448 return strtod_l (&buffer[0],
nullptr, locale);
456 template <
typename CharPo
interType>
459 return readDoubleValue (text);
464 template <
typename IntType,
typename CharPo
interType>
467 using UIntType =
typename internal::make_unsigned<IntType>::type;
470 auto s = text.findEndOfWhitespace();
471 const bool isNeg = *s ==
'-';
478 auto c = s.getAndAdvance();
480 if (c >=
'0' && c <=
'9')
481 v = v * 10 + (UIntType) (c -
'0');
486 return isNeg ? - (IntType) v : (IntType) v;
490 template <
typename ResultType>
493 static_assert (std::is_unsigned_v<ResultType>,
"ResultType must be unsigned because "
494 "left-shifting a negative value is UB");
496 template <
typename CharPo
interType>
497 static ResultType parse (CharPointerType t)
noexcept
499 ResultType result = 0;
501 while (! t.isEmpty())
503 auto hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
506 result =
static_cast<ResultType
> (result << 4) | static_cast<ResultType> (hexValue);
516 template <
typename CharPo
interType>
517 static size_t lengthUpTo (CharPointerType text,
const size_t maxCharsToCount)
noexcept
521 while (len < maxCharsToCount && text.getAndAdvance() != 0)
529 template <
typename CharPo
interType>
530 static size_t lengthUpTo (CharPointerType start,
const CharPointerType end)
noexcept
534 while (start < end && start.getAndAdvance() != 0)
541 template <
typename DestCharPo
interType,
typename SrcCharPo
interType>
542 static void copyAll (DestCharPointerType& dest, SrcCharPointerType src)
noexcept
544 while (
auto c = src.getAndAdvance())
552 template <
typename DestCharPo
interType,
typename SrcCharPo
interType>
553 static size_t copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src,
size_t maxBytesToWrite)
noexcept
555 auto startAddress = dest.getAddress();
556 auto maxBytes = (
ssize_t) maxBytesToWrite;
557 maxBytes -= (
ssize_t)
sizeof (
typename DestCharPointerType::CharType);
561 auto c = src.getAndAdvance();
562 auto bytesNeeded = (
ssize_t) DestCharPointerType::getBytesRequiredFor (c);
563 maxBytes -= bytesNeeded;
565 if (c == 0 || maxBytes < 0)
574 +
sizeof (
typename DestCharPointerType::CharType);
579 template <
typename DestCharPo
interType,
typename SrcCharPo
interType>
580 static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src,
int maxChars)
noexcept
582 while (--maxChars > 0)
584 auto c = src.getAndAdvance();
598 if (
auto diff =
static_cast<int> (char1) -
static_cast<int> (char2))
599 return diff < 0 ? -1 : 1;
605 template <
typename CharPo
interType1,
typename CharPo
interType2>
606 static int compare (CharPointerType1 s1, CharPointerType2 s2)
noexcept
610 auto c1 = s1.getAndAdvance();
612 if (
auto diff = compare (c1, s2.getAndAdvance()))
623 template <
typename CharPo
interType1,
typename CharPo
interType2>
624 static int compareUpTo (CharPointerType1 s1, CharPointerType2 s2,
int maxChars)
noexcept
626 while (--maxChars >= 0)
628 auto c1 = s1.getAndAdvance();
630 if (
auto diff = compare (c1, s2.getAndAdvance()))
643 return char1 != char2 ? compare (toUpperCase (char1), toUpperCase (char2)) : 0;
647 template <
typename CharPo
interType1,
typename CharPo
interType2>
652 auto c1 = s1.getAndAdvance();
654 if (
auto diff = compareIgnoreCase (c1, s2.getAndAdvance()))
665 template <
typename CharPo
interType1,
typename CharPo
interType2>
668 while (--maxChars >= 0)
670 auto c1 = s1.getAndAdvance();
672 if (
auto diff = compareIgnoreCase (c1, s2.getAndAdvance()))
685 template <
typename CharPo
interType1,
typename CharPo
interType2>
686 static int indexOf (CharPointerType1 textToSearch,
const CharPointerType2 substringToLookFor)
noexcept
689 auto substringLength = (
int) substringToLookFor.length();
693 if (textToSearch.compareUpTo (substringToLookFor, substringLength) == 0)
696 if (textToSearch.getAndAdvance() == 0)
707 template <
typename CharPo
interType1,
typename CharPo
interType2>
708 static CharPointerType1
find (CharPointerType1 textToSearch,
const CharPointerType2 substringToLookFor)
noexcept
710 auto substringLength = (
int) substringToLookFor.length();
712 while (textToSearch.compareUpTo (substringToLookFor, substringLength) != 0
713 && ! textToSearch.isEmpty())
723 template <
typename CharPo
interType>
724 static CharPointerType
find (CharPointerType textToSearch,
const juce_wchar charToLookFor)
noexcept
726 for (;; ++textToSearch)
728 auto c = *textToSearch;
730 if (c == charToLookFor || c == 0)
741 template <
typename CharPo
interType1,
typename CharPo
interType2>
742 static int indexOfIgnoreCase (CharPointerType1 haystack,
const CharPointerType2 needle)
noexcept
745 auto needleLength = (
int) needle.length();
749 if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
752 if (haystack.getAndAdvance() == 0)
762 template <
typename Type>
767 while (! text.isEmpty())
769 if (text.getAndAdvance() == charToFind)
782 template <
typename Type>
785 charToFind = CharacterFunctions::toLowerCase (charToFind);
788 while (! text.isEmpty())
790 if (text.toLowerCase() == charToFind)
806 template <
typename Type>
809 while (text.isWhitespace())
817 template <
typename Type>
820 incrementToEndOfWhitespace (text);
827 template <
typename Type,
typename BreakType>
828 static Type
findEndOfToken (Type text, BreakType breakCharacters, Type quoteCharacters)
832 while (! text.isEmpty())
834 auto c = text.getAndAdvance();
836 if (currentQuoteChar == 0 && breakCharacters.indexOf (c) >= 0)
842 if (quoteCharacters.indexOf (c) >= 0)
844 if (currentQuoteChar == 0)
845 currentQuoteChar = c;
846 else if (currentQuoteChar == c)
847 currentQuoteChar = 0;
855 static double mulexp10 (
double value,
int exponent)
noexcept;
A collection of functions for manipulating characters and character strings.
static int indexOfIgnoreCase(CharPointerType1 haystack, const CharPointerType2 needle) noexcept
Finds the character index of a given substring in another string, using a case-independent match.
static void incrementToEndOfWhitespace(Type &text) noexcept
Increments a pointer until it points to the first non-whitespace character in a string.
static int compare(juce_wchar char1, juce_wchar char2) noexcept
Compares two characters.
static size_t copyWithDestByteLimit(DestCharPointerType &dest, SrcCharPointerType src, size_t maxBytesToWrite) noexcept
Copies characters from one string to another, up to a null terminator or a given byte size limit.
static int indexOfCharIgnoreCase(Type text, juce_wchar charToFind) noexcept
Finds the character index of a given character in another string, using a case-independent match.
static IntType getIntValue(const CharPointerType text) noexcept
Parses a character string, to read an integer value.
static int compareIgnoreCaseUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
Compares two null-terminated character strings, using a case-independent match.
static int indexOfChar(Type text, const juce_wchar charToFind) noexcept
Finds the character index of a given character in another string.
static int compare(CharPointerType1 s1, CharPointerType2 s2) noexcept
Compares two null-terminated character strings.
static int compareIgnoreCase(juce_wchar char1, juce_wchar char2) noexcept
Compares two characters, using a case-independant match.
static size_t lengthUpTo(CharPointerType start, const CharPointerType end) noexcept
Counts the number of characters in a given string, stopping if the count exceeds a specified end-poin...
static int indexOf(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
Finds the character index of a given substring in another string.
static size_t lengthUpTo(CharPointerType text, const size_t maxCharsToCount) noexcept
Counts the number of characters in a given string, stopping if the count exceeds a specified limit.
static double readDoubleValue(CharPointerType &text) noexcept
Parses a character string to read a floating-point number.
static CharPointerType find(CharPointerType textToSearch, const juce_wchar charToLookFor) noexcept
Returns a pointer to the first occurrence of a substring in a string.
static Type findEndOfWhitespace(Type text) noexcept
Returns a pointer to the first non-whitespace character in a string.
static void copyWithCharLimit(DestCharPointerType &dest, SrcCharPointerType src, int maxChars) noexcept
Copies characters from one string to another, up to a null terminator or a given maximum number of ch...
static Type findEndOfToken(Type text, BreakType breakCharacters, Type quoteCharacters)
Returns a pointer to the first character in the string which is found in the breakCharacters string.
static CharPointerType1 find(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
Returns a pointer to the first occurrence of a substring in a string.
static int compareIgnoreCase(CharPointerType1 s1, CharPointerType2 s2) noexcept
Compares two null-terminated character strings, using a case-independant match.
static double getDoubleValue(CharPointerType text) noexcept
Parses a character string, to read a floating-point value.
static void copyAll(DestCharPointerType &dest, SrcCharPointerType src) noexcept
Copies null-terminated characters from one string to another.
static int compareUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
Compares two null-terminated character strings, up to a given number of characters.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
int getAddressDifference(Type1 *pointer1, Type2 *pointer2) noexcept
A handy function which returns the difference between any two pointers, in bytes.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
Parses a character string, to read a hexadecimal value.