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