1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
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 
23 namespace juce
24 {
25 
26 //==============================================================================
27 /**
28     Wraps a pointer to a null-terminated UTF-32 character string, and provides
29     various methods to operate on the data.
30     @see CharPointer_UTF8, CharPointer_UTF16
31 
32     @tags{Core}
33 */
34 class CharPointer_UTF32  final
35 {
36 public:
37     using CharType = juce_wchar;
38 
CharPointer_UTF32(const CharType * rawPointer)39     inline explicit CharPointer_UTF32 (const CharType* rawPointer) noexcept
40         : data (const_cast<CharType*> (rawPointer))
41     {
42     }
43 
44     inline CharPointer_UTF32 (const CharPointer_UTF32& other) = default;
45 
46     inline CharPointer_UTF32 operator= (CharPointer_UTF32 other) noexcept
47     {
48         data = other.data;
49         return *this;
50     }
51 
52     inline CharPointer_UTF32 operator= (const CharType* text) noexcept
53     {
54         data = const_cast<CharType*> (text);
55         return *this;
56     }
57 
58     /** This is a pointer comparison, it doesn't compare the actual text. */
59     inline bool operator== (CharPointer_UTF32 other) const noexcept     { return data == other.data; }
60     inline bool operator!= (CharPointer_UTF32 other) const noexcept     { return data != other.data; }
61     inline bool operator<= (CharPointer_UTF32 other) const noexcept     { return data <= other.data; }
62     inline bool operator<  (CharPointer_UTF32 other) const noexcept     { return data <  other.data; }
63     inline bool operator>= (CharPointer_UTF32 other) const noexcept     { return data >= other.data; }
64     inline bool operator>  (CharPointer_UTF32 other) const noexcept     { return data >  other.data; }
65 
66     /** Returns the address that this pointer is pointing to. */
getAddress()67     inline CharType* getAddress() const noexcept        { return data; }
68 
69     /** Returns the address that this pointer is pointing to. */
70     inline operator const CharType*() const noexcept    { return data; }
71 
72     /** Returns true if this pointer is pointing to a null character. */
isEmpty()73     inline bool isEmpty() const noexcept                { return *data == 0; }
74 
75     /** Returns true if this pointer is not pointing to a null character. */
isNotEmpty()76     inline bool isNotEmpty() const noexcept             { return *data != 0; }
77 
78     /** Returns the unicode character that this pointer is pointing to. */
79     inline juce_wchar operator*() const noexcept        { return *data; }
80 
81     /** Moves this pointer along to the next character in the string. */
82     inline CharPointer_UTF32 operator++() noexcept
83     {
84         ++data;
85         return *this;
86     }
87 
88     /** Moves this pointer to the previous character in the string. */
89     inline CharPointer_UTF32 operator--() noexcept
90     {
91         --data;
92         return *this;
93     }
94 
95     /** Returns the character that this pointer is currently pointing to, and then
96         advances the pointer to point to the next character. */
getAndAdvance()97     inline juce_wchar getAndAdvance() noexcept  { return *data++; }
98 
99     /** Moves this pointer along to the next character in the string. */
100     CharPointer_UTF32 operator++ (int) noexcept
101     {
102         auto temp (*this);
103         ++data;
104         return temp;
105     }
106 
107     /** Moves this pointer forwards by the specified number of characters. */
108     inline void operator+= (int numToSkip) noexcept
109     {
110         data += numToSkip;
111     }
112 
113     inline void operator-= (int numToSkip) noexcept
114     {
115         data -= numToSkip;
116     }
117 
118     /** Returns the character at a given character index from the start of the string. */
119     inline juce_wchar& operator[] (int characterIndex) const noexcept
120     {
121         return data [characterIndex];
122     }
123 
124     /** Returns a pointer which is moved forwards from this one by the specified number of characters. */
125     CharPointer_UTF32 operator+ (int numToSkip) const noexcept
126     {
127         return CharPointer_UTF32 (data + numToSkip);
128     }
129 
130     /** Returns a pointer which is moved backwards from this one by the specified number of characters. */
131     CharPointer_UTF32 operator- (int numToSkip) const noexcept
132     {
133         return CharPointer_UTF32 (data - numToSkip);
134     }
135 
136     /** Writes a unicode character to this string, and advances this pointer to point to the next position. */
write(juce_wchar charToWrite)137     inline void write (juce_wchar charToWrite) noexcept
138     {
139         *data++ = charToWrite;
140     }
141 
replaceChar(juce_wchar newChar)142     inline void replaceChar (juce_wchar newChar) noexcept
143     {
144         *data = newChar;
145     }
146 
147     /** Writes a null character to this string (leaving the pointer's position unchanged). */
writeNull()148     inline void writeNull() const noexcept
149     {
150         *data = 0;
151     }
152 
153     /** Returns the number of characters in this string. */
length()154     size_t length() const noexcept
155     {
156        #if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
157         return wcslen (data);
158        #else
159         size_t n = 0;
160         while (data[n] != 0)
161             ++n;
162         return n;
163        #endif
164     }
165 
166     /** Returns the number of characters in this string, or the given value, whichever is lower. */
lengthUpTo(size_t maxCharsToCount)167     size_t lengthUpTo (size_t maxCharsToCount) const noexcept
168     {
169         return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
170     }
171 
172     /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
lengthUpTo(CharPointer_UTF32 end)173     size_t lengthUpTo (CharPointer_UTF32 end) const noexcept
174     {
175         return CharacterFunctions::lengthUpTo (*this, end);
176     }
177 
178     /** Returns the number of bytes that are used to represent this string.
179         This includes the terminating null character.
180     */
sizeInBytes()181     size_t sizeInBytes() const noexcept
182     {
183         return sizeof (CharType) * (length() + 1);
184     }
185 
186     /** Returns the number of bytes that would be needed to represent the given
187         unicode character in this encoding format.
188     */
getBytesRequiredFor(juce_wchar)189     static size_t getBytesRequiredFor (juce_wchar) noexcept
190     {
191         return sizeof (CharType);
192     }
193 
194     /** Returns the number of bytes that would be needed to represent the given
195         string in this encoding format.
196         The value returned does NOT include the terminating null character.
197     */
198     template <class CharPointer>
getBytesRequiredFor(CharPointer text)199     static size_t getBytesRequiredFor (CharPointer text) noexcept
200     {
201         return sizeof (CharType) * text.length();
202     }
203 
204     /** Returns a pointer to the null character that terminates this string. */
findTerminatingNull()205     CharPointer_UTF32 findTerminatingNull() const noexcept
206     {
207         return CharPointer_UTF32 (data + length());
208     }
209 
210     /** Copies a source string to this pointer, advancing this pointer as it goes. */
211     template <typename CharPointer>
writeAll(CharPointer src)212     void writeAll (CharPointer src) noexcept
213     {
214         CharacterFunctions::copyAll (*this, src);
215     }
216 
217     /** Copies a source string to this pointer, advancing this pointer as it goes. */
writeAll(CharPointer_UTF32 src)218     void writeAll (CharPointer_UTF32 src) noexcept
219     {
220         auto* s = src.data;
221 
222         while ((*data = *s) != 0)
223         {
224             ++data;
225             ++s;
226         }
227     }
228 
229     /** Copies a source string to this pointer, advancing this pointer as it goes.
230         The maxDestBytes parameter specifies the maximum number of bytes that can be written
231         to the destination buffer before stopping.
232     */
233     template <typename CharPointer>
writeWithDestByteLimit(CharPointer src,size_t maxDestBytes)234     size_t writeWithDestByteLimit (CharPointer src, size_t maxDestBytes) noexcept
235     {
236         return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
237     }
238 
239     /** Copies a source string to this pointer, advancing this pointer as it goes.
240         The maxChars parameter specifies the maximum number of characters that can be
241         written to the destination buffer before stopping (including the terminating null).
242     */
243     template <typename CharPointer>
writeWithCharLimit(CharPointer src,int maxChars)244     void writeWithCharLimit (CharPointer src, int maxChars) noexcept
245     {
246         CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
247     }
248 
249     /** Compares this string with another one. */
250     template <typename CharPointer>
compare(CharPointer other)251     int compare (CharPointer other) const noexcept
252     {
253         return CharacterFunctions::compare (*this, other);
254     }
255 
256    #if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
257     /** Compares this string with another one. */
compare(CharPointer_UTF32 other)258     int compare (CharPointer_UTF32 other) const noexcept
259     {
260         return wcscmp (data, other.data);
261     }
262    #endif
263 
264     /** Compares this string with another one, up to a specified number of characters. */
265     template <typename CharPointer>
compareUpTo(CharPointer other,int maxChars)266     int compareUpTo (CharPointer other, int maxChars) const noexcept
267     {
268         return CharacterFunctions::compareUpTo (*this, other, maxChars);
269     }
270 
271     /** Compares this string with another one. */
272     template <typename CharPointer>
compareIgnoreCase(CharPointer other)273     int compareIgnoreCase (CharPointer other) const
274     {
275         return CharacterFunctions::compareIgnoreCase (*this, other);
276     }
277 
278     /** Compares this string with another one, up to a specified number of characters. */
279     template <typename CharPointer>
compareIgnoreCaseUpTo(CharPointer other,int maxChars)280     int compareIgnoreCaseUpTo (CharPointer other, int maxChars) const noexcept
281     {
282         return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
283     }
284 
285     /** Returns the character index of a substring, or -1 if it isn't found. */
286     template <typename CharPointer>
indexOf(CharPointer stringToFind)287     int indexOf (CharPointer stringToFind) const noexcept
288     {
289         return CharacterFunctions::indexOf (*this, stringToFind);
290     }
291 
292     /** Returns the character index of a unicode character, or -1 if it isn't found. */
indexOf(juce_wchar charToFind)293     int indexOf (juce_wchar charToFind) const noexcept
294     {
295         int i = 0;
296 
297         while (data[i] != 0)
298         {
299             if (data[i] == charToFind)
300                 return i;
301 
302             ++i;
303         }
304 
305         return -1;
306     }
307 
308     /** Returns the character index of a unicode character, or -1 if it isn't found. */
indexOf(juce_wchar charToFind,bool ignoreCase)309     int indexOf (juce_wchar charToFind, bool ignoreCase) const noexcept
310     {
311         return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
312                           : CharacterFunctions::indexOfChar (*this, charToFind);
313     }
314 
315     /** Returns true if the first character of this string is whitespace. */
isWhitespace()316     bool isWhitespace() const                   { return CharacterFunctions::isWhitespace (*data) != 0; }
317     /** Returns true if the first character of this string is a digit. */
isDigit()318     bool isDigit() const                        { return CharacterFunctions::isDigit (*data) != 0; }
319     /** Returns true if the first character of this string is a letter. */
isLetter()320     bool isLetter() const                       { return CharacterFunctions::isLetter (*data) != 0; }
321     /** Returns true if the first character of this string is a letter or digit. */
isLetterOrDigit()322     bool isLetterOrDigit() const                { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
323     /** Returns true if the first character of this string is upper-case. */
isUpperCase()324     bool isUpperCase() const                    { return CharacterFunctions::isUpperCase (*data) != 0; }
325     /** Returns true if the first character of this string is lower-case. */
isLowerCase()326     bool isLowerCase() const                    { return CharacterFunctions::isLowerCase (*data) != 0; }
327 
328     /** Returns an upper-case version of the first character of this string. */
toUpperCase()329     juce_wchar toUpperCase() const noexcept     { return CharacterFunctions::toUpperCase (*data); }
330     /** Returns a lower-case version of the first character of this string. */
toLowerCase()331     juce_wchar toLowerCase() const noexcept     { return CharacterFunctions::toLowerCase (*data); }
332 
333     /** Parses this string as a 32-bit integer. */
getIntValue32()334     int getIntValue32() const noexcept          { return CharacterFunctions::getIntValue <int, CharPointer_UTF32> (*this); }
335     /** Parses this string as a 64-bit integer. */
getIntValue64()336     int64 getIntValue64() const noexcept        { return CharacterFunctions::getIntValue <int64, CharPointer_UTF32> (*this); }
337 
338     /** Parses this string as a floating point double. */
getDoubleValue()339     double getDoubleValue() const noexcept      { return CharacterFunctions::getDoubleValue (*this); }
340 
341     /** Returns the first non-whitespace character in the string. */
findEndOfWhitespace()342     CharPointer_UTF32 findEndOfWhitespace() const noexcept   { return CharacterFunctions::findEndOfWhitespace (*this); }
343 
344     /** Move this pointer to the first non-whitespace character in the string. */
incrementToEndOfWhitespace()345     void incrementToEndOfWhitespace() noexcept               { CharacterFunctions::incrementToEndOfWhitespace (*this); }
346 
347     /** Returns true if the given unicode character can be represented in this encoding. */
canRepresent(juce_wchar character)348     static bool canRepresent (juce_wchar character) noexcept
349     {
350         return ((uint32) character) < (uint32) 0x10ffff;
351     }
352 
353     /** Returns true if this data contains a valid string in this encoding. */
isValidString(const CharType * dataToTest,int maxBytesToRead)354     static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
355     {
356         maxBytesToRead /= (int) sizeof (CharType);
357 
358         while (--maxBytesToRead >= 0 && *dataToTest != 0)
359             if (! canRepresent (*dataToTest++))
360                 return false;
361 
362         return true;
363     }
364 
365     /** Atomically swaps this pointer for a new value, returning the previous value. */
atomicSwap(CharPointer_UTF32 newValue)366     CharPointer_UTF32 atomicSwap (CharPointer_UTF32 newValue)
367     {
368         return CharPointer_UTF32 (reinterpret_cast<Atomic<CharType*>&> (data).exchange (newValue.data));
369     }
370 
371 private:
372     CharType* data;
373 };
374 
375 } // namespace juce
376