OpenShot Audio Library | OpenShotAudio 0.3.2
Loading...
Searching...
No Matches
juce_CharacterFunctions.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26//==============================================================================
27#if JUCE_WINDOWS && ! 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
31#else
33 #define JUCE_NATIVE_WCHAR_IS_UTF8 0
35 #define JUCE_NATIVE_WCHAR_IS_UTF16 0
37 #define JUCE_NATIVE_WCHAR_IS_UTF32 1
38#endif
39
40#if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
42 using juce_wchar = wchar_t;
43#else
44 using juce_wchar = uint32;
45#endif
46
47#ifndef DOXYGEN
49 #define JUCE_T(stringLiteral) (L##stringLiteral)
50#endif
51
52#if JUCE_DEFINE_T_MACRO
60 #define T(stringLiteral) JUCE_T(stringLiteral)
61#endif
62
63#if ! DOXYGEN
64
65//==============================================================================
66// GNU libstdc++ does not have std::make_unsigned
67namespace internal
68{
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; };
76}
77
78#endif
79
80//==============================================================================
91class JUCE_API CharacterFunctions
92{
93public:
94 //==============================================================================
96 static juce_wchar toUpperCase (juce_wchar character) noexcept;
98 static juce_wchar toLowerCase (juce_wchar character) noexcept;
99
101 static bool isUpperCase (juce_wchar character) noexcept;
103 static bool isLowerCase (juce_wchar character) noexcept;
104
106 static bool isWhitespace (char character) noexcept;
108 static bool isWhitespace (juce_wchar character) noexcept;
109
111 static bool isDigit (char character) noexcept;
113 static bool isDigit (juce_wchar character) noexcept;
114
116 static bool isLetter (char character) noexcept;
118 static bool isLetter (juce_wchar character) noexcept;
119
121 static bool isLetterOrDigit (char character) noexcept;
123 static bool isLetterOrDigit (juce_wchar character) noexcept;
124
128 static bool isPrintable (char character) noexcept;
129
133 static bool isPrintable (juce_wchar character) noexcept;
134
136 static int getHexDigitValue (juce_wchar digit) noexcept;
137
139 static juce_wchar getUnicodeCharFromWindows1252Codepage (uint8 windows1252Char) noexcept;
140
141 //==============================================================================
146 template <typename CharPointerType>
147 static double readDoubleValue (CharPointerType& text) noexcept
148 {
149 #if JUCE_MINGW
150 bool isNegative = false;
151 #else
152 JUCE_CONSTEXPR const int maxSignificantDigits = 17 + 1; // An additional digit for rounding
153 JUCE_CONSTEXPR const int bufferSize = maxSignificantDigits + 7 + 1; // -.E-XXX and a trailing null-terminator
154 char buffer[(size_t) bufferSize] = {};
155 char* currentCharacter = &(buffer[0]);
156 #endif
157
158 text = text.findEndOfWhitespace();
159 auto c = *text;
160
161 switch (c)
162 {
163 case '-':
164 #if JUCE_MINGW
165 isNegative = true;
166 #else
167 *currentCharacter++ = '-';
168 #endif
169 // Fall-through..
170 case '+':
171 c = *++text;
172 }
173
174 switch (c)
175 {
176 case 'n':
177 case 'N':
178 if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N'))
179 return std::numeric_limits<double>::quiet_NaN();
180 break;
181
182 case 'i':
183 case 'I':
184 if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F'))
185 return std::numeric_limits<double>::infinity();
186 break;
187 }
188
189 #if JUCE_MINGW
190 // MinGW does not have access to the locale functions required for strtold, so we parse the doubles
191 // ourselves. There are some edge cases where the least significant digit will be wrong!
192 double result[3] = { 0 }, accumulator[2] = { 0 };
193 int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
194 int exponent = 0, decPointIndex = 0, digit = 0;
195 int lastDigit = 0, numSignificantDigits = 0;
196 bool digitsFound = false;
197 JUCE_CONSTEXPR const int maxSignificantDigits = 17 + 1;
198
199 for (;;)
200 {
201 if (text.isDigit())
202 {
204 digit = (int) text.getAndAdvance() - '0';
205 digitsFound = true;
206
207 if (decPointIndex != 0)
209
210 if (numSignificantDigits == 0 && digit == 0)
211 continue;
212
214 {
215 if (digit > 5)
217 else if (digit == 5 && (lastDigit & 1) != 0)
219
220 if (decPointIndex > 0)
222 else
224
225 while (text.isDigit())
226 {
227 ++text;
228 if (decPointIndex == 0)
230 }
231 }
232 else
233 {
234 const auto maxAccumulatorValue = (double) ((std::numeric_limits<unsigned int>::max() - 9) / 10);
236 {
237 result [decPointIndex] = mulexp10 (result [decPointIndex], exponentAccumulator [decPointIndex])
241 }
242
245 }
246 }
247 else if (decPointIndex == 0 && *text == '.')
248 {
249 ++text;
250 decPointIndex = 1;
251
253 {
254 while (text.isDigit())
255 ++text;
256 break;
257 }
258 }
259 else
260 {
261 break;
262 }
263 }
264
265 result[0] = mulexp10 (result[0], exponentAccumulator[0]) + accumulator[0];
266
267 if (decPointIndex != 0)
268 result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1];
269
270 c = *text;
271 if ((c == 'e' || c == 'E') && digitsFound)
272 {
273 auto negativeExponent = false;
274
275 switch (*++text)
276 {
277 case '-': negativeExponent = true; // fall-through..
278 case '+': ++text;
279 }
280
281 while (text.isDigit())
282 exponent = (exponent * 10) + ((int) text.getAndAdvance() - '0');
283
286 }
287
288 auto r = mulexp10 (result[0], exponent + exponentAdjustment[0]);
289 if (decPointIndex != 0)
290 r += mulexp10 (result[1], exponent - exponentAdjustment[1]);
291
292 return isNegative ? -r : r;
293
294 #else // ! JUCE_MINGW
295
296 int numSigFigs = 0;
297 bool decimalPointFound = false;
298 int extraExponent = 0;
299
300 for (;;)
301 {
302 if (text.isDigit())
303 {
304 auto digit = (int) text.getAndAdvance() - '0';
305
307 {
309 continue;
310 }
311 else
312 {
314 {
316 continue;
317 }
318
319 if (numSigFigs == 0 && digit == 0)
320 continue;
321 }
322
323 *currentCharacter++ = (char) ('0' + (char) digit);
324 numSigFigs++;
325 }
326 else if ((! decimalPointFound) && *text == '.')
327 {
328 ++text;
329 *currentCharacter++ = '.';
330 decimalPointFound = true;
331 }
332 else
333 {
334 break;
335 }
336 }
337
338 c = *text;
339
340 auto writeExponentDigits = [](int exponent, char* destination)
341 {
342 auto exponentDivisor = 100;
343
344 while (exponentDivisor > 1)
345 {
347 *destination++ = (char) ('0' + (char) digit);
349 exponentDivisor /= 10;
350 }
351
352 *destination++ = (char) ('0' + (char) exponent);
353 };
354
355 if ((c == 'e' || c == 'E') && numSigFigs > 0)
356 {
357 *currentCharacter++ = 'e';
358 bool parsedExponentIsPositive = true;
359
360 switch (*++text)
361 {
362 case '-': parsedExponentIsPositive = false; // Fall-through..
363 case '+': ++text;
364 }
365
366 int exponent = 0;
367
368 while (text.isDigit())
369 {
370 auto digit = (int) text.getAndAdvance() - '0';
371
372 if (digit != 0 || exponent != 0)
373 exponent = (exponent * 10) + digit;
374 }
375
377
378 if (exponent < 0)
379 *currentCharacter++ = '-';
380
381 exponent = std::abs (exponent);
382
383 if (exponent > std::numeric_limits<double>::max_exponent10)
384 return std::numeric_limits<double>::quiet_NaN();
385
387 }
388 else if (extraExponent > 0)
389 {
390 *currentCharacter++ = 'e';
392 }
393
394 #if JUCE_WINDOWS
395 static _locale_t locale = _create_locale (LC_ALL, "C");
396 return _strtod_l (&buffer[0], nullptr, locale);
397 #else
398 static locale_t locale = newlocale (LC_ALL_MASK, "C", nullptr);
399 #if JUCE_ANDROID
400 return (double) strtold_l (&buffer[0], nullptr, locale);
401 #else
402 return strtod_l (&buffer[0], nullptr, locale);
403 #endif
404 #endif
405
406 #endif // JUCE_MINGW
407 }
408
410 template <typename CharPointerType>
411 static double getDoubleValue (CharPointerType text) noexcept
412 {
413 return readDoubleValue (text);
414 }
415
416 //==============================================================================
418 template <typename IntType, typename CharPointerType>
419 static IntType getIntValue (const CharPointerType text) noexcept
420 {
422
423 UIntType v = 0;
424 auto s = text.findEndOfWhitespace();
425 const bool isNeg = *s == '-';
426
427 if (isNeg)
428 ++s;
429
430 for (;;)
431 {
432 auto c = s.getAndAdvance();
433
434 if (c >= '0' && c <= '9')
435 v = v * 10 + (UIntType) (c - '0');
436 else
437 break;
438 }
439
440 return isNeg ? - (IntType) v : (IntType) v;
441 }
442
444 template <typename ResultType>
446 {
447 template <typename CharPointerType>
448 static ResultType parse (CharPointerType t) noexcept
449 {
450 ResultType result = 0;
451
452 while (! t.isEmpty())
453 {
454 auto hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
455
456 if (hexValue >= 0)
457 result = (result << 4) | hexValue;
458 }
459
460 return result;
461 }
462 };
463
464 //==============================================================================
467 template <typename CharPointerType>
468 static size_t lengthUpTo (CharPointerType text, const size_t maxCharsToCount) noexcept
469 {
470 size_t len = 0;
471
472 while (len < maxCharsToCount && text.getAndAdvance() != 0)
473 ++len;
474
475 return len;
476 }
477
480 template <typename CharPointerType>
481 static size_t lengthUpTo (CharPointerType start, const CharPointerType end) noexcept
482 {
483 size_t len = 0;
484
485 while (start < end && start.getAndAdvance() != 0)
486 ++len;
487
488 return len;
489 }
490
492 template <typename DestCharPointerType, typename SrcCharPointerType>
493 static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) noexcept
494 {
495 while (auto c = src.getAndAdvance())
496 dest.write (c);
497
498 dest.writeNull();
499 }
500
503 template <typename DestCharPointerType, typename SrcCharPointerType>
505 {
506 auto startAddress = dest.getAddress();
508 maxBytes -= (ssize_t) sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null)
509
510 for (;;)
511 {
512 auto c = src.getAndAdvance();
513 auto bytesNeeded = (ssize_t) DestCharPointerType::getBytesRequiredFor (c);
515
516 if (c == 0 || maxBytes < 0)
517 break;
518
519 dest.write (c);
520 }
521
522 dest.writeNull();
523
524 return (size_t) getAddressDifference (dest.getAddress(), startAddress)
525 + sizeof (typename DestCharPointerType::CharType);
526 }
527
530 template <typename DestCharPointerType, typename SrcCharPointerType>
532 {
533 while (--maxChars > 0)
534 {
535 auto c = src.getAndAdvance();
536
537 if (c == 0)
538 break;
539
540 dest.write (c);
541 }
542
543 dest.writeNull();
544 }
545
547 static inline int compare (juce_wchar char1, juce_wchar char2) noexcept
548 {
549 if (auto diff = static_cast<int> (char1) - static_cast<int> (char2))
550 return diff < 0 ? -1 : 1;
551
552 return 0;
553 }
554
556 template <typename CharPointerType1, typename CharPointerType2>
557 static int compare (CharPointerType1 s1, CharPointerType2 s2) noexcept
558 {
559 for (;;)
560 {
561 auto c1 = s1.getAndAdvance();
562
563 if (auto diff = compare (c1, s2.getAndAdvance()))
564 return diff;
565
566 if (c1 == 0)
567 break;
568 }
569
570 return 0;
571 }
572
574 template <typename CharPointerType1, typename CharPointerType2>
575 static int compareUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
576 {
577 while (--maxChars >= 0)
578 {
579 auto c1 = s1.getAndAdvance();
580
581 if (auto diff = compare (c1, s2.getAndAdvance()))
582 return diff;
583
584 if (c1 == 0)
585 break;
586 }
587
588 return 0;
589 }
590
592 static inline int compareIgnoreCase (juce_wchar char1, juce_wchar char2) noexcept
593 {
594 return char1 != char2 ? compare (toUpperCase (char1), toUpperCase (char2)) : 0;
595 }
596
598 template <typename CharPointerType1, typename CharPointerType2>
600 {
601 for (;;)
602 {
603 auto c1 = s1.getAndAdvance();
604
605 if (auto diff = compareIgnoreCase (c1, s2.getAndAdvance()))
606 return diff;
607
608 if (c1 == 0)
609 break;
610 }
611
612 return 0;
613 }
614
616 template <typename CharPointerType1, typename CharPointerType2>
618 {
619 while (--maxChars >= 0)
620 {
621 auto c1 = s1.getAndAdvance();
622
623 if (auto diff = compareIgnoreCase (c1, s2.getAndAdvance()))
624 return diff;
625
626 if (c1 == 0)
627 break;
628 }
629
630 return 0;
631 }
632
636 template <typename CharPointerType1, typename CharPointerType2>
638 {
639 int index = 0;
640 auto substringLength = (int) substringToLookFor.length();
641
642 for (;;)
643 {
644 if (textToSearch.compareUpTo (substringToLookFor, substringLength) == 0)
645 return index;
646
647 if (textToSearch.getAndAdvance() == 0)
648 return -1;
649
650 ++index;
651 }
652 }
653
658 template <typename CharPointerType1, typename CharPointerType2>
660 {
661 auto substringLength = (int) substringToLookFor.length();
662
663 while (textToSearch.compareUpTo (substringToLookFor, substringLength) != 0
664 && ! textToSearch.isEmpty())
665 ++textToSearch;
666
667 return textToSearch;
668 }
669
674 template <typename CharPointerType>
675 static CharPointerType find (CharPointerType textToSearch, const juce_wchar charToLookFor) noexcept
676 {
677 for (;; ++textToSearch)
678 {
679 auto c = *textToSearch;
680
681 if (c == charToLookFor || c == 0)
682 break;
683 }
684
685 return textToSearch;
686 }
687
692 template <typename CharPointerType1, typename CharPointerType2>
694 {
695 int index = 0;
696 auto needleLength = (int) needle.length();
697
698 for (;;)
699 {
700 if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
701 return index;
702
703 if (haystack.getAndAdvance() == 0)
704 return -1;
705
706 ++index;
707 }
708 }
709
713 template <typename Type>
714 static int indexOfChar (Type text, const juce_wchar charToFind) noexcept
715 {
716 int i = 0;
717
718 while (! text.isEmpty())
719 {
720 if (text.getAndAdvance() == charToFind)
721 return i;
722
723 ++i;
724 }
725
726 return -1;
727 }
728
733 template <typename Type>
734 static int indexOfCharIgnoreCase (Type text, juce_wchar charToFind) noexcept
735 {
736 charToFind = CharacterFunctions::toLowerCase (charToFind);
737 int i = 0;
738
739 while (! text.isEmpty())
740 {
741 if (text.toLowerCase() == charToFind)
742 return i;
743
744 ++text;
745 ++i;
746 }
747
748 return -1;
749 }
750
755 template <typename Type>
756 static Type findEndOfWhitespace (Type text) noexcept
757 {
758 while (text.isWhitespace())
759 ++text;
760
761 return text;
762 }
763
767 template <typename Type, typename BreakType>
769 {
770 juce_wchar currentQuoteChar = 0;
771
772 while (! text.isEmpty())
773 {
774 auto c = text.getAndAdvance();
775
776 if (currentQuoteChar == 0 && breakCharacters.indexOf (c) >= 0)
777 {
778 --text;
779 break;
780 }
781
782 if (quoteCharacters.indexOf (c) >= 0)
783 {
784 if (currentQuoteChar == 0)
786 else if (currentQuoteChar == c)
788 }
789 }
790
791 return text;
792 }
793
794private:
795 static double mulexp10 (double value, int exponent) noexcept;
796};
797
798} // namespace juce
bool isEmpty() const noexcept
Definition juce_Array.h:222
int indexOf(ParameterType elementToLookFor) const
Definition juce_Array.h:382
static int indexOfIgnoreCase(CharPointerType1 haystack, const CharPointerType2 needle) noexcept
static int compare(juce_wchar char1, juce_wchar char2) noexcept
static size_t copyWithDestByteLimit(DestCharPointerType &dest, SrcCharPointerType src, size_t maxBytesToWrite) noexcept
static int indexOfCharIgnoreCase(Type text, juce_wchar charToFind) noexcept
static IntType getIntValue(const CharPointerType text) noexcept
static int compareIgnoreCaseUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
static int indexOfChar(Type text, const juce_wchar charToFind) noexcept
static int compare(CharPointerType1 s1, CharPointerType2 s2) noexcept
static int compareIgnoreCase(juce_wchar char1, juce_wchar char2) noexcept
static size_t lengthUpTo(CharPointerType start, const CharPointerType end) noexcept
static int indexOf(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
static size_t lengthUpTo(CharPointerType text, const size_t maxCharsToCount) noexcept
static double readDoubleValue(CharPointerType &text) noexcept
static CharPointerType find(CharPointerType textToSearch, const juce_wchar charToLookFor) noexcept
static Type findEndOfWhitespace(Type text) noexcept
static void copyWithCharLimit(DestCharPointerType &dest, SrcCharPointerType src, int maxChars) noexcept
static Type findEndOfToken(Type text, BreakType breakCharacters, Type quoteCharacters)
static CharPointerType1 find(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
static int compareIgnoreCase(CharPointerType1 s1, CharPointerType2 s2) noexcept
static double getDoubleValue(CharPointerType text) noexcept
static void copyAll(DestCharPointerType &dest, SrcCharPointerType src) noexcept
static int compareUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept