From 3bacbe2a8cb413be7de9895c973760226bf970b3 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Mon, 31 Jan 2011 17:59:38 +0000 Subject: [PATCH] Refactored various string processing in the library. Removed a couple of String accessors that relied on assumptions about the format of the string's internal data (if your code has any problems with these changes, you should probably use the String::getCharPointer() method instead). --- .../Source/Utility/jucer_CodeHelpers.cpp | 24 +- juce_amalgamated.cpp | 732 ++++++++---------- juce_amalgamated.h | 97 ++- src/core/juce_StandardHeader.h | 2 +- src/core/juce_Time.cpp | 2 +- src/cryptography/juce_MD5.cpp | 8 +- .../juce_CPlusPlusCodeTokeniser.cpp | 8 +- .../code_editor/juce_CodeDocument.cpp | 52 +- .../components/controls/juce_TextEditor.cpp | 47 +- .../positioning/juce_RelativePoint.cpp | 17 +- .../positioning/juce_RelativeRectangle.cpp | 25 +- src/gui/graphics/drawables/juce_SVGParser.cpp | 161 ++-- .../graphics/fonts/juce_GlyphArrangement.cpp | 4 +- src/gui/graphics/fonts/juce_TextLayout.cpp | 6 +- src/gui/graphics/fonts/juce_Typeface.cpp | 12 +- src/gui/graphics/geometry/juce_Path.cpp | 21 +- src/io/files/juce_File.cpp | 10 +- src/io/files/juce_File.h | 2 +- src/io/streams/juce_MemoryOutputStream.cpp | 2 +- src/io/streams/juce_OutputStream.cpp | 25 +- src/io/streams/juce_OutputStream.h | 10 +- src/maths/juce_BigInteger.cpp | 6 +- src/maths/juce_Expression.cpp | 126 +-- src/maths/juce_Expression.h | 7 +- src/memory/juce_MemoryBlock.cpp | 14 +- src/native/mac/juce_mac_Fonts.mm | 10 +- src/native/mac/juce_mac_Strings.mm | 2 +- src/native/windows/juce_win32_Messaging.cpp | 2 +- .../juce_win32_QuickTimeMovieComponent.cpp | 9 +- src/text/juce_CharacterFunctions.h | 45 +- src/text/juce_String.cpp | 44 +- src/text/juce_String.h | 22 +- src/text/juce_StringArray.cpp | 73 +- src/text/juce_StringArray.h | 4 +- src/text/juce_StringPool.cpp | 24 +- src/text/juce_StringPool.h | 6 +- src/text/juce_XmlElement.cpp | 12 +- 37 files changed, 780 insertions(+), 893 deletions(-) diff --git a/extras/Jucer (experimental)/Source/Utility/jucer_CodeHelpers.cpp b/extras/Jucer (experimental)/Source/Utility/jucer_CodeHelpers.cpp index 81649a1fbd..c581b974ac 100644 --- a/extras/Jucer (experimental)/Source/Utility/jucer_CodeHelpers.cpp +++ b/extras/Jucer (experimental)/Source/Utility/jucer_CodeHelpers.cpp @@ -104,16 +104,15 @@ namespace CodeHelpers return n; } - template - static void writeEscapeChars (OutputStream& out, const CharType* data, const int numChars, + static void writeEscapeChars (OutputStream& out, const char* utf8, const int numBytes, const int maxCharsOnLine, const bool breakAtNewLines, const bool replaceSingleQuotes) { int charsOnLine = 0; bool lastWasHexEscapeCode = false; - for (int i = 0; i < numChars || numChars < 0; ++i) + for (int i = 0; i < numBytes || numBytes < 0; ++i) { - const CharType c = data[i]; + const char c = utf8[i]; bool startNewLine = false; switch (c) @@ -125,7 +124,7 @@ namespace CodeHelpers case '\"': out << "\\\""; lastWasHexEscapeCode = false; break; case 0: - if (numChars < 0) + if (numBytes < 0) return; out << "\\0"; @@ -144,9 +143,9 @@ namespace CodeHelpers default: if (c >= 32 && c < 127 && ! (lastWasHexEscapeCode // (have to avoid following a hex escape sequence with a valid hex digit) - && ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))) + && CharacterFunctions::getHexDigitValue (c) >= 0)) { - out << (char) c; + out << c; lastWasHexEscapeCode = false; } else @@ -159,7 +158,7 @@ namespace CodeHelpers } if ((startNewLine || (maxCharsOnLine > 0 && ++charsOnLine >= maxCharsOnLine)) - && (numChars < 0 || i < numChars - 1)) + && (numBytes < 0 || i < numBytes - 1)) { charsOnLine = 0; out << "\"" << newLine << "\""; @@ -170,7 +169,7 @@ namespace CodeHelpers const String addEscapeChars (const String& s) { MemoryOutputStream out; - writeEscapeChars (out, (const juce_wchar*) s, -1, -1, false, true); + writeEscapeChars (out, s.toUTF8().getAddress(), -1, -1, false, true); return out.toUTF8(); } @@ -192,7 +191,10 @@ namespace CodeHelpers if (text.isEmpty()) return "String::empty"; - return CodeHelpers::addEscapeChars (text).quoted(); + if (CharPointer_ASCII::isValidString (text.toUTF8(), std::numeric_limits::max())) + return CodeHelpers::addEscapeChars (text).quoted(); + else + return "CharPointer_UTF8 (" + CodeHelpers::addEscapeChars (text).quoted() + ")"; } const String stringLiteralIfNotEmpty (const String& text) @@ -423,7 +425,7 @@ namespace CodeHelpers else { out << "\""; - writeEscapeChars (out, data, (int) mb.getSize(), maxCharsOnLine, true, false); + writeEscapeChars (out, (const char*) data, (int) mb.getSize(), maxCharsOnLine, true, false); out << "\";"; } } diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index e20993a974..174e1cb736 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -1995,7 +1995,7 @@ const String Time::formatted (const String& format) const struct tm t (TimeHelpers::millisToLocal (millisSinceEpoch)); - while (CharacterFunctions::ftime (static_cast (buffer), bufferSize, format, &t) <= 0) + while (CharacterFunctions::ftime (buffer.getCharPointer().getAddress(), bufferSize, format.getCharPointer(), &t) <= 0) { bufferSize += 128; buffer.preallocateStorage (bufferSize); @@ -3487,7 +3487,7 @@ const String BigInteger::toString (const int base, const int minimumNumCharacter void BigInteger::parseString (const String& text, const int base) { clear(); - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); if (base == 2 || base == 8 || base == 16) { @@ -3495,7 +3495,7 @@ void BigInteger::parseString (const String& text, const int base) for (;;) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); const int digit = CharacterFunctions::getHexDigitValue (c); if (((uint32) digit) < (uint32) base) @@ -3515,7 +3515,7 @@ void BigInteger::parseString (const String& text, const int base) for (;;) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); if (c >= '0' && c <= '9') { @@ -3857,15 +3857,14 @@ const String MemoryBlock::toBase64Encoding() const const int initialLen = destString.length(); destString.preallocateStorage (initialLen + 2 + numChars); - juce_wchar* d = destString; + String::CharPointerType d (destString.getCharPointer()); d += initialLen; - *d++ = '.'; + d.write ('.'); for (size_t i = 0; i < numChars; ++i) - *d++ = encodingTable [getBitRange (i * 6, 6)]; - - *d++ = 0; + d.write (encodingTable [getBitRange (i * 6, 6)]); + d.writeNull(); return destString; } @@ -3881,13 +3880,14 @@ bool MemoryBlock::fromBase64Encoding (const String& s) setSize (numBytesNeeded, true); const int numChars = s.length() - startPos; - const juce_wchar* srcChars = s; + + String::CharPointerType srcChars (s.getCharPointer()); srcChars += startPos; int pos = 0; for (int i = 0; i < numChars; ++i) { - const char c = (char) srcChars[i]; + const char c = (char) srcChars.getAndAdvance(); for (int j = 0; j < 64; ++j) { @@ -5424,46 +5424,37 @@ public: { public: - Parser (const String& stringToParse, int& textIndex_) - : textString (stringToParse), textIndex (textIndex_) + Parser (String::CharPointerType& stringToParse) + : text (stringToParse) { - text = textString; } const TermPtr readUpToComma() { - if (textString.isEmpty()) + if (text.isEmpty()) return new Constant (0.0, false); const TermPtr e (readExpression()); - if (e == 0 || ((! readOperator (",")) && text [textIndex] != 0)) - throw ParseError ("Syntax error: \"" + textString.substring (textIndex) + "\""); + if (e == 0 || ((! readOperator (",")) && ! text.isEmpty())) + throw ParseError ("Syntax error: \"" + String (text) + "\""); return e; } private: - const String textString; - const juce_wchar* text; - int& textIndex; + String::CharPointerType& text; static inline bool isDecimalDigit (const juce_wchar c) throw() { return c >= '0' && c <= '9'; } - void skipWhitespace (int& i) throw() - { - while (CharacterFunctions::isWhitespace (text [i])) - ++i; - } - bool readChar (const juce_wchar required) throw() { - if (text[textIndex] == required) + if (*text == required) { - ++textIndex; + ++text; return true; } @@ -5472,7 +5463,7 @@ public: bool readOperator (const char* ops, char* const opType = 0) throw() { - skipWhitespace (textIndex); + text = text.findEndOfWhitespace(); while (*ops != 0) { @@ -5492,21 +5483,26 @@ public: bool readIdentifier (String& identifier) throw() { - skipWhitespace (textIndex); - int i = textIndex; + text = text.findEndOfWhitespace(); + String::CharPointerType t (text); + int numChars = 0; - if (CharacterFunctions::isLetter (text[i]) || text[i] == '_') + if (t.isLetter() || *t == '_') { - ++i; + ++t; + ++numChars; - while (CharacterFunctions::isLetterOrDigit (text[i]) || text[i] == '_') - ++i; + while (t.isLetterOrDigit() || *t == '_') + { + ++t; + ++numChars; + } } - if (i > textIndex) + if (numChars > 0) { - identifier = String (text + textIndex, i - textIndex); - textIndex = i; + identifier = String (text, numChars); + text = t; return true; } @@ -5515,71 +5511,27 @@ public: Term* readNumber() throw() { - skipWhitespace (textIndex); - int i = textIndex; + text = text.findEndOfWhitespace(); + String::CharPointerType t (text); - const bool isResolutionTarget = (text[i] == '@'); + const bool isResolutionTarget = (*t == '@'); if (isResolutionTarget) { - ++i; - skipWhitespace (i); - textIndex = i; + ++t; + t = t.findEndOfWhitespace(); + text = t; } - if (text[i] == '-') + if (*t == '-') { - ++i; - skipWhitespace (i); + ++t; + t = t.findEndOfWhitespace(); } - int numDigits = 0; + if (isDecimalDigit (*t) || (*t == '.' && isDecimalDigit (t[1]))) + return new Constant (CharacterFunctions::readDoubleValue (text), isResolutionTarget); - while (isDecimalDigit (text[i])) - { - ++i; - ++numDigits; - } - - const bool hasPoint = (text[i] == '.'); - - if (hasPoint) - { - ++i; - - while (isDecimalDigit (text[i])) - { - ++i; - ++numDigits; - } - } - - if (numDigits == 0) - return 0; - - juce_wchar c = text[i]; - const bool hasExponent = (c == 'e' || c == 'E'); - - if (hasExponent) - { - ++i; - c = text[i]; - if (c == '+' || c == '-') - ++i; - - int numExpDigits = 0; - while (isDecimalDigit (text[i])) - { - ++i; - ++numExpDigits; - } - - if (numExpDigits == 0) - return 0; - } - - const int start = textIndex; - textIndex = i; - return new Constant (String (text + start, i - start).getDoubleValue(), isResolutionTarget); + return 0; } const TermPtr readExpression() @@ -5764,14 +5716,14 @@ Expression& Expression::operator= (const Expression& other) Expression::Expression (const String& stringToParse) { - int i = 0; - Helpers::Parser parser (stringToParse, i); + String::CharPointerType text (stringToParse.getCharPointer()); + Helpers::Parser parser (text); term = parser.readUpToComma(); } -const Expression Expression::parse (const String& stringToParse, int& textIndexToStartFrom) +const Expression Expression::parse (String::CharPointerType& stringToParse) { - Helpers::Parser parser (stringToParse, textIndexToStartFrom); + Helpers::Parser parser (stringToParse); return Expression (parser.readUpToComma()); } @@ -6271,15 +6223,13 @@ MD5::MD5 (const void* data, const size_t numBytes) MD5::MD5 (const String& text) { ProcessContext context; + String::CharPointerType t (text.getCharPointer()); - const int len = text.length(); - const juce_wchar* const t = text; - - for (int i = 0; i < len; ++i) + while (! t.isEmpty()) { // force the string into integer-sized unicode characters, to try to make it // get the same results on all platforms + compilers. - uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t[i]); + uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t.getAndAdvance()); context.processBlock (&unicodeChar, sizeof (unicodeChar)); } @@ -7202,24 +7152,29 @@ void OutputStream::writeString (const String& text) write (temp, numBytes); } -void OutputStream::writeText (const String& text, const bool asUnicode, - const bool writeUnicodeHeaderBytes) +void OutputStream::writeText (const String& text, const bool asUTF16, + const bool writeUTF16ByteOrderMark) { - if (asUnicode) + if (asUTF16) { - if (writeUnicodeHeaderBytes) + if (writeUTF16ByteOrderMark) write ("\x0ff\x0fe", 2); - const juce_wchar* src = text; + String::CharPointerType src (text.getCharPointer()); bool lastCharWasReturn = false; - while (*src != 0) + for (;;) { - if (*src == L'\n' && ! lastCharWasReturn) - writeShort ((short) L'\r'); + const juce_wchar c = src.getAndAdvance(); - lastCharWasReturn = (*src == L'\r'); - writeShort ((short) *src++); + if (c == 0) + break; + + if (c == '\n' && ! lastCharWasReturn) + writeShort ((short) '\r'); + + lastCharWasReturn = (c == L'\r'); + writeShort ((short) c); } } else @@ -8249,11 +8204,8 @@ const String File::getRelativePathFrom (const File& dir) const { String thisPath (fullPath); - { - int len = thisPath.length(); - while (--len >= 0 && thisPath [len] == File::separator) - thisPath [len] = 0; - } + while (thisPath.endsWithChar (separator)) + thisPath = thisPath.dropLastCharacters (1); String dirPath (addTrailingSeparator (dir.existsAsFile() ? dir.getParentDirectory().getFullPathName() : dir.fullPath)); @@ -8405,6 +8357,9 @@ public: expect (tempFile.loadFileAsString() == "0123456789"); expect (! demoFolder.containsSubDirectories()); + expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() + File::separatorString + tempFile.getFileName()); + expectEquals (demoFolder.getParentDirectory().getRelativePathFrom (tempFile), ".." + File::separatorString + ".." + File::separatorString + demoFolder.getParentDirectory().getFileName()); + expect (demoFolder.getNumberOfChildFiles (File::findFiles) == 1); expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 1); expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 0); @@ -10417,7 +10372,7 @@ int MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumB const String MemoryOutputStream::toUTF8() const { - return String (static_cast (getData()), getDataSize()); + return String::fromUTF8 (static_cast (getData()), getDataSize()); } const String MemoryOutputStream::toString() const @@ -11849,6 +11804,12 @@ int String::length() const throw() return (int) text.length(); } +const juce_wchar String::operator[] (int index) const throw() +{ + jassert (index == 0 || isPositiveAndNotGreaterThan (index, length())); + return text [index]; +} + int String::hashCode() const throw() { const juce_wchar* t = text; @@ -12766,13 +12727,6 @@ const String String::toLowerCase() const return result; } -juce_wchar& String::operator[] (const int index) -{ - jassert (isPositiveAndNotGreaterThan (index, length())); - text = StringHolder::makeUnique (text); - return text [index]; -} - juce_wchar String::getLastCharacter() const throw() { return isEmpty() ? juce_wchar() : text [length() - 1]; @@ -12881,18 +12835,16 @@ bool String::isQuotedString() const const String String::unquoted() const { - String s (*this); + const int len = length(); - if (s.text[0] == '"' || s.text[0] == '\'') - s = s.substring (1); + if (len == 0) + return empty; - const int lastCharIndex = s.length() - 1; + const juce_wchar lastChar = text [len - 1]; + const int dropAtStart = (*text == '"' || *text == '\'') ? 1 : 0; + const int dropAtEnd = (lastChar == '"' || lastChar == '\'') ? 1 : 0; - if (lastCharIndex >= 0 - && (s [lastCharIndex] == '"' || s[lastCharIndex] == '\'')) - s [lastCharIndex] = 0; - - return s; + return substring (dropAtStart, len - dropAtEnd); } const String String::quoted (const juce_wchar quoteCharacter) const @@ -12942,15 +12894,12 @@ const String String::trimStart() const if (isEmpty()) return empty; - CharPointerType t (text); - - while (t.isWhitespace()) - ++t; + CharPointerType t (text.findEndOfWhitespace()); if (t == text) return *this; - return String (t.getAddress()); + return String (t); } const String String::trimEnd() const @@ -13324,20 +13273,20 @@ const String String::createStringFromData (const void* const data_, const int si result.preallocateStorage (numChars + 2); const uint16* const src = (const uint16*) (data + 2); - juce_wchar* const dst = const_cast (static_cast (result)); + CharPointerType dst (result.getCharPointer()); if (bigEndian) { for (int i = 0; i < numChars; ++i) - dst[i] = (juce_wchar) ByteOrder::swapIfLittleEndian (src[i]); + dst.write ((juce_wchar) ByteOrder::swapIfLittleEndian (src[i])); } else { for (int i = 0; i < numChars; ++i) - dst[i] = (juce_wchar) ByteOrder::swapIfBigEndian (src[i]); + dst.write ((juce_wchar) ByteOrder::swapIfBigEndian (src[i])); } - dst [numChars] = 0; + dst.writeNull(); return result; } else @@ -14120,12 +14069,15 @@ int StringArray::addTokens (const String& text, const String& breakCharacters, c { bool insideQuotes = false; juce_wchar currentQuoteChar = 0; - int i = 0; - int tokenStart = 0; + + String::CharPointerType t (text.getCharPointer()); + String::CharPointerType tokenStart (t); + int numChars = 0; for (;;) { - const juce_wchar c = text[i]; + const juce_wchar c = t.getAndAdvance(); + ++numChars; const bool isBreak = (c == 0) || ((! insideQuotes) && breakCharacters.containsChar (c)); @@ -14149,16 +14101,14 @@ int StringArray::addTokens (const String& text, const String& breakCharacters, c } else { - add (String (static_cast (text) + tokenStart, i - tokenStart)); - + add (String (tokenStart, numChars - 1)); ++num; - tokenStart = i + 1; + tokenStart = t; + numChars = 0; } if (c == 0) break; - - ++i; } } @@ -14168,41 +14118,39 @@ int StringArray::addTokens (const String& text, const String& breakCharacters, c int StringArray::addLines (const String& sourceText) { int numLines = 0; - const juce_wchar* text = sourceText; + String::CharPointerType text (sourceText.getCharPointer()); + bool finished = text.isEmpty(); - while (*text != 0) + while (! finished) { - const juce_wchar* const startOfLine = text; + String::CharPointerType startOfLine (text); + int numChars = 0; - while (*text != 0) + for (;;) { - if (*text == '\r') + const juce_wchar c = text.getAndAdvance(); + + if (c == 0) + { + finished = true; + break; + } + + if (c == '\n') + break; + + if (c == '\r') { - ++text; if (*text == '\n') ++text; break; } - if (*text == '\n') - { - ++text; - break; - } - - ++text; + ++numChars; } - const juce_wchar* endOfLine = text; - if (endOfLine > startOfLine && (*(endOfLine - 1) == '\r' || *(endOfLine - 1) == '\n')) - --endOfLine; - - if (endOfLine > startOfLine && (*(endOfLine - 1) == '\r' || *(endOfLine - 1) == '\n')) - --endOfLine; - - add (String (startOfLine, jmax (0, (int) (endOfLine - startOfLine)))); - + add (String (startOfLine, numChars)); ++numLines; } @@ -14231,15 +14179,15 @@ void StringArray::removeDuplicates (const bool ignoreCase) void StringArray::appendNumbersToDuplicates (const bool ignoreCase, const bool appendNumberToFirstInstance, - const juce_wchar* preNumberString, - const juce_wchar* postNumberString) + CharPointer_UTF8 preNumberString, + CharPointer_UTF8 postNumberString) { - String defaultPre (" ("), defaultPost (")"); // (these aren't literals because of non-unicode literals on Android) + CharPointer_UTF8 defaultPre (" ("), defaultPost (")"); - if (preNumberString == 0) + if (preNumberString.getAddress() == 0) preNumberString = defaultPre; - if (postNumberString == 0) + if (postNumberString.getAddress() == 0) postNumberString = defaultPost; for (int i = 0; i < size() - 1; ++i) @@ -14255,13 +14203,13 @@ void StringArray::appendNumbersToDuplicates (const bool ignoreCase, int number = 0; if (appendNumberToFirstInstance) - s = original + preNumberString + String (++number) + postNumberString; + s = original + String (preNumberString) + String (++number) + String (postNumberString); else ++number; while (nextIndex >= 0) { - set (nextIndex, (*this)[nextIndex] + preNumberString + String (++number) + postNumberString); + set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString)); nextIndex = indexOf (original, ignoreCase, nextIndex + 1); } } @@ -14408,7 +14356,7 @@ StringPool::~StringPool() {} namespace StringPoolHelpers { template - const juce_wchar* getPooledStringFromArray (Array& strings, StringType newString) + const String::CharPointerType getPooledStringFromArray (Array& strings, StringType newString) { int start = 0; int end = strings.size(); @@ -14419,14 +14367,14 @@ namespace StringPoolHelpers { jassert (start <= end); strings.insert (start, newString); - return strings.getReference (start); + return strings.getReference (start).getCharPointer(); } else { const String& startString = strings.getReference (start); if (startString == newString) - return startString; + return startString.getCharPointer(); const int halfway = (start + end) >> 1; @@ -14436,13 +14384,13 @@ namespace StringPoolHelpers ++start; strings.insert (start, newString); - return strings.getReference (start); + return strings.getReference (start).getCharPointer(); } const int comp = strings.getReference (halfway).compare (newString); if (comp == 0) - return strings.getReference (halfway); + return strings.getReference (halfway).getCharPointer(); else if (comp < 0) start = halfway; else @@ -14452,26 +14400,26 @@ namespace StringPoolHelpers } } -const juce_wchar* StringPool::getPooledString (const String& s) +const String::CharPointerType StringPool::getPooledString (const String& s) { if (s.isEmpty()) - return String::empty; + return String::empty.getCharPointer(); return StringPoolHelpers::getPooledStringFromArray (strings, s); } -const juce_wchar* StringPool::getPooledString (const char* const s) +const String::CharPointerType StringPool::getPooledString (const char* const s) { if (s == 0 || *s == 0) - return String::empty; + return String::empty.getCharPointer(); return StringPoolHelpers::getPooledStringFromArray (strings, s); } -const juce_wchar* StringPool::getPooledString (const juce_wchar* const s) +const String::CharPointerType StringPool::getPooledString (const juce_wchar* const s) { if (s == 0 || *s == 0) - return String::empty; + return String::empty.getCharPointer(); return StringPoolHelpers::getPooledStringFromArray (strings, s); } @@ -14483,7 +14431,7 @@ int StringPool::size() const throw() const juce_wchar* StringPool::operator[] (const int index) const throw() { - return strings [index]; + return strings [index].getCharPointer(); } END_JUCE_NAMESPACE @@ -15332,8 +15280,8 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const String& name_, const Strin { #if JUCE_DEBUG // this checks whether the attribute name string contains any illegal characters.. - for (const juce_wchar* t = name; *t != 0; ++t) - jassert (CharacterFunctions::isLetterOrDigit (*t) || *t == '_' || *t == '-' || *t == ':'); + for (String::CharPointerType t (name.getCharPointer()); ! t.isEmpty(); ++t) + jassert (t.isLetterOrDigit() || *t == '_' || *t == '-' || *t == ':'); #endif } @@ -15438,16 +15386,16 @@ namespace XmlOutputFunctions void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, const bool changeNewLines) { - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); for (;;) { - const juce_wchar character = *t++; + const uint32 character = (uint32) t.getAndAdvance(); if (character == 0) break; - if (isLegalXmlChar ((uint32) character)) + if (isLegalXmlChar (character)) { outputStream << (char) character; } @@ -15469,7 +15417,7 @@ namespace XmlOutputFunctions } // Note: deliberate fall-through here! default: - outputStream << "&#" << ((int) (unsigned int) character) << ';'; + outputStream << "&#" << ((int) character) << ';'; break; } } @@ -44495,7 +44443,7 @@ BEGIN_JUCE_NAMESPACE class CodeDocumentLine { public: - CodeDocumentLine (const juce_wchar* const line_, + CodeDocumentLine (const String::CharPointerType& line_, const int lineLength_, const int numNewLineChars, const int lineStartInFile_) @@ -44506,51 +44454,59 @@ public: { } - ~CodeDocumentLine() - { - } - static void createLines (Array & newLines, const String& text) { - const juce_wchar* const t = text; - int pos = 0; + String::CharPointerType t (text.getCharPointer()); + int charNumInFile = 0; + bool finished = t.isEmpty(); - while (t [pos] != 0) + while (! finished) { - const int startOfLine = pos; + String::CharPointerType startOfLine (t); + int startOfLineInFile = charNumInFile; + int lineLength = 0; int numNewLineChars = 0; - while (t[pos] != 0) + for (;;) { - if (t[pos] == '\r') + const juce_wchar c = t.getAndAdvance(); + + if (c == 0) + { + finished = true; + break; + } + + ++charNumInFile; + ++lineLength; + + if (c == '\r') { ++numNewLineChars; - ++pos; - if (t[pos] == '\n') + if (*t == '\n') { + ++t; + ++charNumInFile; + ++lineLength; ++numNewLineChars; - ++pos; } break; } - if (t[pos] == '\n') + if (c == '\n') { ++numNewLineChars; - ++pos; break; } - - ++pos; } - newLines.add (new CodeDocumentLine (t + startOfLine, pos - startOfLine, - numNewLineChars, startOfLine)); + newLines.add (new CodeDocumentLine (startOfLine, lineLength, + numNewLineChars, startOfLineInFile)); } - jassert (pos == text.length()); + jassert (charNumInFile == text.length()); } bool endsWithLineBreak() const throw() @@ -45163,7 +45119,7 @@ void CodeDocument::checkLastLineStatus() if (lastLine != 0 && lastLine->endsWithLineBreak()) { // check that there's an empty line at the end if the preceding one ends in a newline.. - lines.add (new CodeDocumentLine (String::empty, 0, 0, lastLine->lineStartInFile + lastLine->lineLength)); + lines.add (new CodeDocumentLine (String::empty.getCharPointer(), 0, 0, lastLine->lineStartInFile + lastLine->lineLength)); } } @@ -46650,7 +46606,7 @@ namespace CppTokeniser || c == '_' || c == '@'; } - bool isReservedKeyword (const juce_wchar* const token, const int tokenLength) throw() + bool isReservedKeyword (String::CharPointerType token, const int tokenLength) throw() { static const char* const keywords2Char[] = { "if", "do", "or", "id", 0 }; @@ -46699,7 +46655,7 @@ namespace CppTokeniser int i = 0; while (k[i] != 0) { - if (k[i][0] == (char) token[0] && CharPointer_UTF8 (k[i]).compare (CharPointer_UTF32 (token)) == 0) + if (token.compare (CharPointer_ASCII (k[i])) == 0) return true; ++i; @@ -46727,7 +46683,7 @@ namespace CppTokeniser { possibleIdentifier [tokenLength] = 0; - if (isReservedKeyword (possibleIdentifier, tokenLength)) + if (isReservedKeyword (CharPointer_UTF32 (possibleIdentifier), tokenLength)) return CPlusPlusCodeTokeniser::tokenType_builtInKeyword; } @@ -47207,7 +47163,7 @@ const Colour CPlusPlusCodeTokeniser::getDefaultColour (const int tokenType) bool CPlusPlusCodeTokeniser::isReservedKeyword (const String& token) throw() { - return CppTokeniser::isReservedKeyword (token, token.length()); + return CppTokeniser::isReservedKeyword (token.getCharPointer(), token.length()); } END_JUCE_NAMESPACE @@ -52207,55 +52163,56 @@ private: void initialiseAtoms (const String& textToParse, const juce_wchar passwordCharacter) { - int i = 0; - const int len = textToParse.length(); - const juce_wchar* const text = textToParse; + String::CharPointerType text (textToParse.getCharPointer()); - while (i < len) + while (! text.isEmpty()) { - int start = i; + int numChars = 0; + String::CharPointerType start (text); // create a whitespace atom unless it starts with non-ws - if (CharacterFunctions::isWhitespace (text[i]) - && text[i] != '\r' - && text[i] != '\n') + if (text.isWhitespace() && *text != '\r' && *text != '\n') { - while (i < len - && CharacterFunctions::isWhitespace (text[i]) - && text[i] != '\r' - && text[i] != '\n') + do { - ++i; + ++text; + ++numChars; } + while (text.isWhitespace() && *text != '\r' && *text != '\n'); } else { - if (text[i] == '\r') + if (*text == '\r') { - ++i; + ++text; + ++numChars; - if ((i < len) && (text[i] == '\n')) + if (*text == '\n') { ++start; - ++i; + ++text; } } - else if (text[i] == '\n') + else if (*text == '\n') { - ++i; + ++text; + ++numChars; } else { - while ((i < len) && ! CharacterFunctions::isWhitespace (text[i])) - ++i; + while (! text.isEmpty() || text.isWhitespace()) + { + ++text; + ++numChars; + } } } TextAtom* const atom = new TextAtom(); - atom->atomText = String (text + start, i - start); + atom->atomText = String (start, numChars); atom->width = font.getStringWidthFloat (atom->getText (passwordCharacter)); - atom->numChars = (uint16) (i - start); + atom->numChars = (uint16) numChars; atoms.add (atom); } @@ -79318,13 +79275,12 @@ BEGIN_JUCE_NAMESPACE namespace RelativePointHelpers { - void skipComma (const juce_wchar* const s, int& i) + inline void skipComma (String::CharPointerType& s) { - while (CharacterFunctions::isWhitespace (s[i])) - ++i; + s = s.findEndOfWhitespace(); - if (s[i] == ',') - ++i; + if (*s == ',') + ++s; } } @@ -79349,10 +79305,10 @@ RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordi RelativePoint::RelativePoint (const String& s) { - int i = 0; - x = RelativeCoordinate (Expression::parse (s, i)); - RelativePointHelpers::skipComma (s, i); - y = RelativeCoordinate (Expression::parse (s, i)); + String::CharPointerType text (s.getCharPointer()); + x = RelativeCoordinate (Expression::parse (text)); + RelativePointHelpers::skipComma (text); + y = RelativeCoordinate (Expression::parse (text)); } bool RelativePoint::operator== (const RelativePoint& other) const throw() @@ -79396,13 +79352,12 @@ BEGIN_JUCE_NAMESPACE namespace RelativeRectangleHelpers { - inline void skipComma (const juce_wchar* const s, int& i) + inline void skipComma (String::CharPointerType& s) { - while (CharacterFunctions::isWhitespace (s[i])) - ++i; + s = s.findEndOfWhitespace(); - if (s[i] == ',') - ++i; + if (*s == ',') + ++s; } bool dependsOnSymbolsOtherThanThis (const Expression& e) @@ -79456,14 +79411,14 @@ RelativeRectangle::RelativeRectangle (const Rectangle& rect) RelativeRectangle::RelativeRectangle (const String& s) { - int i = 0; - left = RelativeCoordinate (Expression::parse (s, i)); - RelativeRectangleHelpers::skipComma (s, i); - top = RelativeCoordinate (Expression::parse (s, i)); - RelativeRectangleHelpers::skipComma (s, i); - right = RelativeCoordinate (Expression::parse (s, i)); - RelativeRectangleHelpers::skipComma (s, i); - bottom = RelativeCoordinate (Expression::parse (s, i)); + String::CharPointerType text (s.getCharPointer()); + left = RelativeCoordinate (Expression::parse (text)); + RelativeRectangleHelpers::skipComma (text); + top = RelativeCoordinate (Expression::parse (text)); + RelativeRectangleHelpers::skipComma (text); + right = RelativeCoordinate (Expression::parse (text)); + RelativeRectangleHelpers::skipComma (text); + bottom = RelativeCoordinate (Expression::parse (text)); } bool RelativeRectangle::operator== (const RelativeRectangle& other) const throw() @@ -88144,10 +88099,6 @@ public: { } - ~SVGState() - { - } - Drawable* parseSVGElement (const XmlElement& xml) { if (! xml.hasTagName ("svg")) @@ -88169,12 +88120,12 @@ public: if (xml.hasAttribute ("viewBox")) { - const String viewParams (xml.getStringAttribute ("viewBox")); - int i = 0; + const String viewBoxAtt (xml.getStringAttribute ("viewBox")); + String::CharPointerType viewParams (viewBoxAtt.getCharPointer()); float vx, vy, vw, vh; - if (parseCoords (viewParams, vx, vy, i, true) - && parseCoords (viewParams, vw, vh, i, true) + if (parseCoords (viewParams, vx, vy, true) + && parseCoords (viewParams, vw, vh, true) && vw > 0 && vh > 0) { @@ -88296,28 +88247,28 @@ private: Drawable* parsePath (const XmlElement& xml) const { - const String d (xml.getStringAttribute ("d").trimStart()); + const String dAttribute (xml.getStringAttribute ("d").trimStart()); + String::CharPointerType d (dAttribute.getCharPointer()); Path path; if (getStyleAttribute (&xml, "fill-rule").trim().equalsIgnoreCase ("evenodd")) path.setUsingNonZeroWinding (false); - int index = 0; float lastX = 0, lastY = 0; float lastX2 = 0, lastY2 = 0; juce_wchar lastCommandChar = 0; bool isRelative = true; bool carryOn = true; - const String validCommandChars ("MmLlHhVvCcSsQqTtAaZz"); + const CharPointer_ASCII validCommandChars ("MmLlHhVvCcSsQqTtAaZz"); - while (d[index] != 0) + while (! d.isEmpty()) { float x, y, x2, y2, x3, y3; - if (validCommandChars.containsChar (d[index])) + if (validCommandChars.indexOf (*d) >= 0) { - lastCommandChar = d [index++]; + lastCommandChar = d.getAndAdvance(); isRelative = (lastCommandChar >= 'a' && lastCommandChar <= 'z'); } @@ -88327,7 +88278,7 @@ private: case 'm': case 'L': case 'l': - if (parseCoords (d, x, y, index, false)) + if (parseCoords (d, x, y, false)) { if (isRelative) { @@ -88350,14 +88301,14 @@ private: } else { - ++index; + ++d; } break; case 'H': case 'h': - if (parseCoord (d, x, index, false, true)) + if (parseCoord (d, x, false, true)) { if (isRelative) x += lastX; @@ -88369,13 +88320,13 @@ private: } else { - ++index; + ++d; } break; case 'V': case 'v': - if (parseCoord (d, y, index, false, false)) + if (parseCoord (d, y, false, false)) { if (isRelative) y += lastY; @@ -88387,15 +88338,15 @@ private: } else { - ++index; + ++d; } break; case 'C': case 'c': - if (parseCoords (d, x, y, index, false) - && parseCoords (d, x2, y2, index, false) - && parseCoords (d, x3, y3, index, false)) + if (parseCoords (d, x, y, false) + && parseCoords (d, x2, y2, false) + && parseCoords (d, x3, y3, false)) { if (isRelative) { @@ -88416,14 +88367,14 @@ private: } else { - ++index; + ++d; } break; case 'S': case 's': - if (parseCoords (d, x, y, index, false) - && parseCoords (d, x3, y3, index, false)) + if (parseCoords (d, x, y, false) + && parseCoords (d, x3, y3, false)) { if (isRelative) { @@ -88444,14 +88395,14 @@ private: } else { - ++index; + ++d; } break; case 'Q': case 'q': - if (parseCoords (d, x, y, index, false) - && parseCoords (d, x2, y2, index, false)) + if (parseCoords (d, x, y, false) + && parseCoords (d, x2, y2, false)) { if (isRelative) { @@ -88470,13 +88421,13 @@ private: } else { - ++index; + ++d; } break; case 'T': case 't': - if (parseCoords (d, x, y, index, false)) + if (parseCoords (d, x, y, false)) { if (isRelative) { @@ -88495,29 +88446,29 @@ private: } else { - ++index; + ++d; } break; case 'A': case 'a': - if (parseCoords (d, x, y, index, false)) + if (parseCoords (d, x, y, false)) { String num; - if (parseNextNumber (d, num, index, false)) + if (parseNextNumber (d, num, false)) { const float angle = num.getFloatValue() * (180.0f / float_Pi); - if (parseNextNumber (d, num, index, false)) + if (parseNextNumber (d, num, false)) { const bool largeArc = num.getIntValue() != 0; - if (parseNextNumber (d, num, index, false)) + if (parseNextNumber (d, num, false)) { const bool sweep = num.getIntValue() != 0; - if (parseCoords (d, x2, y2, index, false)) + if (parseCoords (d, x2, y2, false)) { if (isRelative) { @@ -88554,7 +88505,7 @@ private: } else { - ++index; + ++d; } break; @@ -88562,9 +88513,7 @@ private: case 'Z': case 'z': path.closeSubPath(); - while (CharacterFunctions::isWhitespace (d [index])) - ++index; - + d = d.findEndOfWhitespace(); break; default: @@ -88657,13 +88606,12 @@ private: Drawable* parsePolygon (const XmlElement& xml, const bool isPolyline) const { - const String points (xml.getStringAttribute ("points")); + const String pointsAtt (xml.getStringAttribute ("points")); + String::CharPointerType points (pointsAtt.getCharPointer()); Path path; - - int index = 0; float x, y; - if (parseCoords (points, x, y, index, true)) + if (parseCoords (points, x, y, true)) { float firstX = x; float firstY = y; @@ -88671,7 +88619,7 @@ private: path.startNewSubPath (x, y); - while (parseCoords (points, x, y, index, true)) + while (parseCoords (points, x, y, true)) { lastX = x; lastY = y; @@ -88955,12 +88903,11 @@ private: .followedBy (transform); } - bool parseCoord (const String& s, float& value, int& index, - const bool allowUnits, const bool isX) const + bool parseCoord (String::CharPointerType& s, float& value, const bool allowUnits, const bool isX) const { String number; - if (! parseNextNumber (s, number, index, allowUnits)) + if (! parseNextNumber (s, number, allowUnits)) { value = 0; return false; @@ -88970,11 +88917,10 @@ private: return true; } - bool parseCoords (const String& s, float& x, float& y, - int& index, const bool allowUnits) const + bool parseCoords (String::CharPointerType& s, float& x, float& y, const bool allowUnits) const { - return parseCoord (s, x, index, allowUnits, true) - && parseCoord (s, y, index, allowUnits, false); + return parseCoord (s, x, allowUnits, true) + && parseCoord (s, y, allowUnits, false); } float getCoordLength (const String& s, const float sizeForProportions) const @@ -89007,10 +88953,10 @@ private: void getCoordList (Array & coords, const String& list, const bool allowUnits, const bool isX) const { - int index = 0; + String::CharPointerType text (list.getCharPointer()); float value; - while (parseCoord (list, value, index, allowUnits, isX)) + while (parseCoord (text, value, allowUnits, isX)) coords.add (value); } @@ -89121,45 +89067,55 @@ private: return defaultValue; } - static bool parseNextNumber (const String& source, String& value, int& index, const bool allowUnits) + static bool parseNextNumber (String::CharPointerType& s, String& value, const bool allowUnits) { - const juce_wchar* const s = source; + while (s.isWhitespace() || *s == ',') + ++s; - while (CharacterFunctions::isWhitespace (s[index]) || s[index] == ',') - ++index; + String::CharPointerType start (s); + int numChars = 0; - int start = index; - - if (CharacterFunctions::isDigit (s[index]) || s[index] == '.' || s[index] == '-') - ++index; - - while (CharacterFunctions::isDigit (s[index]) || s[index] == '.') - ++index; - - if ((s[index] == 'e' || s[index] == 'E') - && (CharacterFunctions::isDigit (s[index + 1]) - || s[index + 1] == '-' - || s[index + 1] == '+')) + if (s.isDigit() || *s == '.' || *s == '-') { - index += 2; + ++numChars; + ++s; + } - while (CharacterFunctions::isDigit (s[index])) - ++index; + while (s.isDigit() || *s == '.') + { + ++numChars; + ++s; + } + + if ((*s == 'e' || *s == 'E') + && ((s + 1).isDigit() || s[1] == '-' || s[1] == '+')) + { + s += 2; + numChars += 2; + + while (s.isDigit()) + { + ++numChars; + ++s; + } } if (allowUnits) { - while (CharacterFunctions::isLetter (s[index])) - ++index; + while (s.isLetter()) + { + ++numChars; + ++s; + } } - if (index == start) + if (numChars == 0) return false; - value = String (s + start, index - start); + value = String (start, numChars); - while (CharacterFunctions::isWhitespace (s[index]) || s[index] == ',') - ++index; + while (s.isWhitespace() || *s == ',') + ++s; return true; } @@ -90180,7 +90136,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, font.getGlyphPositions (text, newGlyphs, xOffsets); const int textLen = newGlyphs.size(); - const juce_wchar* const unicodeText = text; + String::CharPointerType t (text.getCharPointer()); for (int i = 0; i < textLen; ++i) { @@ -90198,7 +90154,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, else { glyphs.add (new PositionedGlyph (xOffset + thisX, yOffset, nextX - thisX, - font, unicodeText[i], newGlyphs.getUnchecked(i))); + font, t.getAndAdvance(), newGlyphs.getUnchecked(i))); } } } @@ -90885,13 +90841,13 @@ bool TextLayout::isEmpty() const void TextLayout::appendText (const String& text, const Font& font) { - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); String currentString; int lastCharType = 0; for (;;) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); if (c == 0) break; @@ -90920,7 +90876,7 @@ void TextLayout::appendText (const String& text, const Font& font) currentString = String::charToString (c); if (c == '\r' && *t == '\n') - currentString += *t++; + currentString += t.getAndAdvance(); } else { @@ -91418,11 +91374,11 @@ float CustomTypeface::getDescent() const float CustomTypeface::getStringWidth (const String& text) { float x = 0; - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); - while (*t != 0) + while (! t.isEmpty()) { - const GlyphInfo* const glyph = findGlyphSubstituting (*t++); + const GlyphInfo* const glyph = findGlyphSubstituting (t.getAndAdvance()); if (glyph == 0 && ! isFallbackFont) { @@ -91443,11 +91399,11 @@ void CustomTypeface::getGlyphPositions (const String& text, Array & resultG { xOffsets.add (0); float x = 0; - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); - while (*t != 0) + while (! t.isEmpty()) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); const GlyphInfo* const glyph = findGlyph (c, true); if (glyph == 0 && ! isFallbackFont) @@ -91737,17 +91693,20 @@ namespace PathHelpers { const float ellipseAngularIncrement = 0.05f; - const String nextToken (const juce_wchar*& t) + const String nextToken (String::CharPointerType& t) { - while (CharacterFunctions::isWhitespace (*t)) + t = t.findEndOfWhitespace(); + + String::CharPointerType start (t); + int numChars = 0; + + while (! (t.isEmpty() || t.isWhitespace())) + { ++t; + ++numChars; + } - const juce_wchar* const start = t; - - while (*t != 0 && ! CharacterFunctions::isWhitespace (*t)) - ++t; - - return String (start, (int) (t - start)); + return String (start, numChars); } inline double lengthOf (float x1, float y1, float x2, float y2) throw() @@ -93134,7 +93093,7 @@ void Path::restoreFromString (const String& stringVersion) clear(); setUsingNonZeroWinding (true); - const juce_wchar* t = stringVersion; + String::CharPointerType t (stringVersion.getCharPointer()); juce_wchar marker = 'm'; int numValues = 2; float values [6]; @@ -239822,7 +239781,7 @@ void MessageManager::broadcastMessage (const String& value) COPYDATASTRUCT data; data.dwData = broadcastId; data.cbData = (localCopy.length() + 1) * sizeof (juce_wchar); - data.lpData = (void*) static_cast (localCopy); + data.lpData = (void*) localCopy.toUTF16().getAddress(); for (int i = windows.size(); --i >= 0;) { @@ -245075,14 +245034,7 @@ static Handle createHandleDataRef (Handle dataHandle, const char* fileName) static CFStringRef juceStringToCFString (const String& s) { - const int len = s.length(); - const juce_wchar* const t = s; - - HeapBlock temp (len + 2); - for (int i = 0; i <= len; ++i) - temp[i] = t[i]; - - return CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); + return CFStringCreateWithCString (kCFAllocatorDefault, s.toUTF8(), kCFStringEncodingUTF8); } static bool openMovie (QTNewMoviePropertyElement* props, int prop, Movie& movie) @@ -262340,7 +262292,7 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) { result.preallocateStorage (bytesRead / sizeof (UniChar) + 2); - CharPointer_UTF32 dest (static_cast (result)); + CharPointer_UTF32 dest (result.getCharPointer()); dest.writeAll (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData())); } @@ -265093,7 +265045,7 @@ public: const int length = text.length(); HeapBlock glyphs; - createGlyphsForString (text, length, glyphs); + createGlyphsForString (text.getCharPointer(), length, glyphs); float x = 0; @@ -265136,7 +265088,7 @@ public: const int length = text.length(); HeapBlock glyphs; - createGlyphsForString (text, length, glyphs); + createGlyphsForString (text.getCharPointer(), length, glyphs); #if SUPPORT_ONLY_10_4_FONTS HeapBlock advances (length); @@ -265237,7 +265189,7 @@ private: AffineTransform pathTransform; #endif - void createGlyphsForString (const juce_wchar* const text, const int length, HeapBlock & glyphs) + void createGlyphsForString (String::CharPointerType text, const int length, HeapBlock & glyphs) { #if SUPPORT_10_4_FONTS #if ! SUPPORT_ONLY_10_4_FONTS @@ -265248,7 +265200,7 @@ private: NSGlyph* const nsGlyphs = reinterpret_cast (glyphs.getData()); for (int i = 0; i < length; ++i) - nsGlyphs[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]]; + nsGlyphs[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text.getAndAdvance()]; return; } @@ -265261,7 +265213,7 @@ private: glyphs.malloc (length); for (int i = 0; i < length; ++i) - glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); + glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text.getAndAdvance()); #endif } @@ -269800,7 +269752,7 @@ public: const int length = text.length(); HeapBlock glyphs; - createGlyphsForString (text, length, glyphs); + createGlyphsForString (text.getCharPointer(), length, glyphs); float x = 0; @@ -269843,7 +269795,7 @@ public: const int length = text.length(); HeapBlock glyphs; - createGlyphsForString (text, length, glyphs); + createGlyphsForString (text.getCharPointer(), length, glyphs); #if SUPPORT_ONLY_10_4_FONTS HeapBlock advances (length); @@ -269944,7 +269896,7 @@ private: AffineTransform pathTransform; #endif - void createGlyphsForString (const juce_wchar* const text, const int length, HeapBlock & glyphs) + void createGlyphsForString (String::CharPointerType text, const int length, HeapBlock & glyphs) { #if SUPPORT_10_4_FONTS #if ! SUPPORT_ONLY_10_4_FONTS @@ -269955,7 +269907,7 @@ private: NSGlyph* const nsGlyphs = reinterpret_cast (glyphs.getData()); for (int i = 0; i < length; ++i) - nsGlyphs[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]]; + nsGlyphs[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text.getAndAdvance()]; return; } @@ -269968,7 +269920,7 @@ private: glyphs.malloc (length); for (int i = 0; i < length; ++i) - glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); + glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text.getAndAdvance()); #endif } diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 8fefffd118..b00ec5fa02 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 23 +#define JUCE_BUILDNUMBER 24 /** Current Juce version number. @@ -1702,7 +1702,7 @@ public: static int getHexDigitValue (juce_wchar digit) throw(); template - static double getDoubleValue (const CharPointerType& text) throw() + static double readDoubleValue (CharPointerType& text) throw() { double result[3] = { 0, 0, 0 }, accumulator[2] = { 0, 0 }; int exponentAdjustment[2] = { 0, 0 }, exponentAccumulator[2] = { -1, -1 }; @@ -1711,36 +1711,36 @@ public: bool isNegative = false, digitsFound = false; const int maxSignificantDigits = 15 + 2; - CharPointerType s (text.findEndOfWhitespace()); - juce_wchar c = *s; + text = text.findEndOfWhitespace(); + juce_wchar c = *text; switch (c) { case '-': isNegative = true; // fall-through.. - case '+': c = *++s; + case '+': c = *++text; } switch (c) { case 'n': case 'N': - if ((s[1] == 'a' || s[1] == 'A') && (s[2] == 'n' || s[2] == 'N')) + if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N')) return std::numeric_limits::quiet_NaN(); break; case 'i': case 'I': - if ((s[1] == 'n' || s[1] == 'N') && (s[2] == 'f' || s[2] == 'F')) + if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F')) return std::numeric_limits::infinity(); break; } for (;;) { - if (s.isDigit()) + if (text.isDigit()) { lastDigit = digit; - digit = s.getAndAdvance() - '0'; + digit = text.getAndAdvance() - '0'; digitsFound = true; if (decPointIndex != 0) @@ -1761,9 +1761,9 @@ public: else exponentAdjustment[0]++; - while (s.isDigit()) + while (text.isDigit()) { - ++s; + ++text; if (decPointIndex == 0) exponentAdjustment[0]++; } @@ -1783,15 +1783,15 @@ public: exponentAccumulator [decPointIndex]++; } } - else if (decPointIndex == 0 && *s == '.') + else if (decPointIndex == 0 && *text == '.') { - ++s; + ++text; decPointIndex = 1; if (numSignificantDigits > maxSignificantDigits) { - while (s.isDigit()) - ++s; + while (text.isDigit()) + ++text; break; } } @@ -1806,19 +1806,19 @@ public: if (decPointIndex != 0) result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1]; - c = *s; + c = *text; if ((c == 'e' || c == 'E') && digitsFound) { bool negativeExponent = false; - switch (*++s) + switch (*++text) { case '-': negativeExponent = true; // fall-through.. - case '+': ++s; + case '+': ++text; } - while (s.isDigit()) - exponent = (exponent * 10) + (s.getAndAdvance() - '0'); + while (text.isDigit()) + exponent = (exponent * 10) + (text.getAndAdvance() - '0'); if (negativeExponent) exponent = -exponent; @@ -1831,6 +1831,13 @@ public: return isNegative ? -r : r; } + template + static double getDoubleValue (const CharPointerType& text) throw() + { + CharPointerType t (text); + return readDoubleValue (t); + } + template static IntType getIntValue (const CharPointerType& text) throw() { @@ -4585,16 +4592,7 @@ public: No checks are made to see if the index is within a valid range, so be careful! */ - inline const juce_wchar& operator[] (int index) const throw() { jassert (isPositiveAndNotGreaterThan (index, length())); return text [index]; } - - /** Returns a character from the string such that it can also be altered. - - This can be used as a way of easily changing characters in the string. - - Note that the index passed-in is not checked to see whether it's in-range, so - be careful when using this. - */ - juce_wchar& operator[] (int index); + const juce_wchar operator[] (int index) const throw(); /** Returns the final character of the string. @@ -5036,15 +5034,7 @@ public: that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ - inline operator const juce_wchar*() const throw() { return text.getAddress(); } - - /** Returns a unicode version of this string. - - Because it returns a reference to the string's internal data, the pointer - that is returned must not be stored anywhere, as it can become invalid whenever - any string methods (even some const ones!) are called. - */ - inline operator juce_wchar*() throw() { return text.getAddress(); } + inline operator const juce_wchar*() const throw() { return toUTF32().getAddress(); } /** Returns the character pointer currently being used to store this string. @@ -7407,7 +7397,7 @@ public: The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ - const juce_wchar* getPooledString (const String& original); + const String::CharPointerType getPooledString (const String& original); /** Returns a pointer to a copy of the string that is passed in. @@ -7415,7 +7405,7 @@ public: The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ - const juce_wchar* getPooledString (const char* original); + const String::CharPointerType getPooledString (const char* original); /** Returns a pointer to a copy of the string that is passed in. @@ -7423,7 +7413,7 @@ public: The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ - const juce_wchar* getPooledString (const juce_wchar* original); + const String::CharPointerType getPooledString (const juce_wchar* original); /** Returns the number of strings in the pool. */ int size() const throw(); @@ -8162,15 +8152,15 @@ public: /** Writes a string of text to the stream. - It can either write it as UTF8 characters or as unicode, and - can also add unicode header bytes (0xff, 0xfe) to indicate the endianness (this - should only be done at the start of a file). + It can either write the text as UTF-8 or UTF-16, and can also add the UTF-16 byte-order-mark + bytes (0xff, 0xfe) to indicate the endianness (these should only be used at the start + of a file). The method also replaces '\\n' characters in the text with '\\r\\n'. */ virtual void writeText (const String& text, - bool asUnicode, - bool writeUnicodeHeaderBytes); + bool asUTF16, + bool writeUTF16ByteOrderMark); /** Reads data from an input stream and writes it to this stream. @@ -10199,8 +10189,8 @@ public: */ void appendNumbersToDuplicates (bool ignoreCaseWhenComparing, bool appendNumberToFirstInstance, - const juce_wchar* preNumberString = 0, - const juce_wchar* postNumberString = 0); + CharPointer_UTF8 preNumberString = CharPointer_UTF8 (0), + CharPointer_UTF8 postNumberString = CharPointer_UTF8 (0)); /** Joins the strings in the array together into one string. @@ -11195,7 +11185,7 @@ public: /** Creates a relative path that refers to a file relatively to a given directory. - e.g. File ("/moose/foo.txt").getRelativePathFrom ("/moose/fish/haddock") + e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock")) would return "../../foo.txt". If it's not possible to navigate from one file to the other, an absolute @@ -20065,15 +20055,16 @@ public: /** Returns an Expression which is a function call. */ static const Expression function (const String& functionName, const Array& parameters); - /** Returns an Expression which parses a string from a specified character index. + /** Returns an Expression which parses a string from a character pointer, and updates the pointer + to indicate where it finished. - The index value is incremented so that on return, it indicates the character that follows + The pointer is incremented so that on return, it indicates the character that follows the end of the expression that was parsed. If there's a syntax error in the string, this will throw a ParseError exception. @throws ParseError */ - static const Expression parse (const String& stringToParse, int& textIndexToStartFrom); + static const Expression parse (String::CharPointerType& stringToParse); /** When evaluating an Expression object, this class is used to resolve symbols and perform functions that the expression uses. diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 474e199530..bca2a4b1ed 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 -#define JUCE_BUILDNUMBER 23 +#define JUCE_BUILDNUMBER 24 /** Current Juce version number. diff --git a/src/core/juce_Time.cpp b/src/core/juce_Time.cpp index 86609a6427..2f1fcb93e5 100644 --- a/src/core/juce_Time.cpp +++ b/src/core/juce_Time.cpp @@ -348,7 +348,7 @@ const String Time::formatted (const String& format) const struct tm t (TimeHelpers::millisToLocal (millisSinceEpoch)); - while (CharacterFunctions::ftime (static_cast (buffer), bufferSize, format, &t) <= 0) + while (CharacterFunctions::ftime (buffer.getCharPointer().getAddress(), bufferSize, format.getCharPointer(), &t) <= 0) { bufferSize += 128; buffer.preallocateStorage (bufferSize); diff --git a/src/cryptography/juce_MD5.cpp b/src/cryptography/juce_MD5.cpp index 94a3aedcfa..dd001ce98b 100644 --- a/src/cryptography/juce_MD5.cpp +++ b/src/cryptography/juce_MD5.cpp @@ -67,15 +67,13 @@ MD5::MD5 (const void* data, const size_t numBytes) MD5::MD5 (const String& text) { ProcessContext context; + String::CharPointerType t (text.getCharPointer()); - const int len = text.length(); - const juce_wchar* const t = text; - - for (int i = 0; i < len; ++i) + while (! t.isEmpty()) { // force the string into integer-sized unicode characters, to try to make it // get the same results on all platforms + compilers. - uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t[i]); + uint32 unicodeChar = ByteOrder::swapIfBigEndian ((uint32) t.getAndAdvance()); context.processBlock (&unicodeChar, sizeof (unicodeChar)); } diff --git a/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp b/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp index e691cabf65..d9c2a8e13c 100644 --- a/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp +++ b/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp @@ -54,7 +54,7 @@ namespace CppTokeniser || c == '_' || c == '@'; } - bool isReservedKeyword (const juce_wchar* const token, const int tokenLength) throw() + bool isReservedKeyword (String::CharPointerType token, const int tokenLength) throw() { static const char* const keywords2Char[] = { "if", "do", "or", "id", 0 }; @@ -103,7 +103,7 @@ namespace CppTokeniser int i = 0; while (k[i] != 0) { - if (k[i][0] == (char) token[0] && CharPointer_UTF8 (k[i]).compare (CharPointer_UTF32 (token)) == 0) + if (token.compare (CharPointer_ASCII (k[i])) == 0) return true; ++i; @@ -131,7 +131,7 @@ namespace CppTokeniser { possibleIdentifier [tokenLength] = 0; - if (isReservedKeyword (possibleIdentifier, tokenLength)) + if (isReservedKeyword (CharPointer_UTF32 (possibleIdentifier), tokenLength)) return CPlusPlusCodeTokeniser::tokenType_builtInKeyword; } @@ -612,7 +612,7 @@ const Colour CPlusPlusCodeTokeniser::getDefaultColour (const int tokenType) bool CPlusPlusCodeTokeniser::isReservedKeyword (const String& token) throw() { - return CppTokeniser::isReservedKeyword (token, token.length()); + return CppTokeniser::isReservedKeyword (token.getCharPointer(), token.length()); } END_JUCE_NAMESPACE diff --git a/src/gui/components/code_editor/juce_CodeDocument.cpp b/src/gui/components/code_editor/juce_CodeDocument.cpp index b6ff749a5d..21530a7c5a 100644 --- a/src/gui/components/code_editor/juce_CodeDocument.cpp +++ b/src/gui/components/code_editor/juce_CodeDocument.cpp @@ -34,7 +34,7 @@ BEGIN_JUCE_NAMESPACE class CodeDocumentLine { public: - CodeDocumentLine (const juce_wchar* const line_, + CodeDocumentLine (const String::CharPointerType& line_, const int lineLength_, const int numNewLineChars, const int lineStartInFile_) @@ -45,51 +45,59 @@ public: { } - ~CodeDocumentLine() - { - } - static void createLines (Array & newLines, const String& text) { - const juce_wchar* const t = text; - int pos = 0; + String::CharPointerType t (text.getCharPointer()); + int charNumInFile = 0; + bool finished = t.isEmpty(); - while (t [pos] != 0) + while (! finished) { - const int startOfLine = pos; + String::CharPointerType startOfLine (t); + int startOfLineInFile = charNumInFile; + int lineLength = 0; int numNewLineChars = 0; - while (t[pos] != 0) + for (;;) { - if (t[pos] == '\r') + const juce_wchar c = t.getAndAdvance(); + + if (c == 0) + { + finished = true; + break; + } + + ++charNumInFile; + ++lineLength; + + if (c == '\r') { ++numNewLineChars; - ++pos; - if (t[pos] == '\n') + if (*t == '\n') { + ++t; + ++charNumInFile; + ++lineLength; ++numNewLineChars; - ++pos; } break; } - if (t[pos] == '\n') + if (c == '\n') { ++numNewLineChars; - ++pos; break; } - - ++pos; } - newLines.add (new CodeDocumentLine (t + startOfLine, pos - startOfLine, - numNewLineChars, startOfLine)); + newLines.add (new CodeDocumentLine (startOfLine, lineLength, + numNewLineChars, startOfLineInFile)); } - jassert (pos == text.length()); + jassert (charNumInFile == text.length()); } bool endsWithLineBreak() const throw() @@ -706,7 +714,7 @@ void CodeDocument::checkLastLineStatus() if (lastLine != 0 && lastLine->endsWithLineBreak()) { // check that there's an empty line at the end if the preceding one ends in a newline.. - lines.add (new CodeDocumentLine (String::empty, 0, 0, lastLine->lineStartInFile + lastLine->lineLength)); + lines.add (new CodeDocumentLine (String::empty.getCharPointer(), 0, 0, lastLine->lineStartInFile + lastLine->lineLength)); } } diff --git a/src/gui/components/controls/juce_TextEditor.cpp b/src/gui/components/controls/juce_TextEditor.cpp index 848f5f0762..d053ddb875 100644 --- a/src/gui/components/controls/juce_TextEditor.cpp +++ b/src/gui/components/controls/juce_TextEditor.cpp @@ -273,55 +273,56 @@ private: void initialiseAtoms (const String& textToParse, const juce_wchar passwordCharacter) { - int i = 0; - const int len = textToParse.length(); - const juce_wchar* const text = textToParse; + String::CharPointerType text (textToParse.getCharPointer()); - while (i < len) + while (! text.isEmpty()) { - int start = i; + int numChars = 0; + String::CharPointerType start (text); // create a whitespace atom unless it starts with non-ws - if (CharacterFunctions::isWhitespace (text[i]) - && text[i] != '\r' - && text[i] != '\n') + if (text.isWhitespace() && *text != '\r' && *text != '\n') { - while (i < len - && CharacterFunctions::isWhitespace (text[i]) - && text[i] != '\r' - && text[i] != '\n') + do { - ++i; + ++text; + ++numChars; } + while (text.isWhitespace() && *text != '\r' && *text != '\n'); } else { - if (text[i] == '\r') + if (*text == '\r') { - ++i; + ++text; + ++numChars; - if ((i < len) && (text[i] == '\n')) + if (*text == '\n') { ++start; - ++i; + ++text; } } - else if (text[i] == '\n') + else if (*text == '\n') { - ++i; + ++text; + ++numChars; } else { - while ((i < len) && ! CharacterFunctions::isWhitespace (text[i])) - ++i; + while (! text.isEmpty() || text.isWhitespace()) + { + ++text; + ++numChars; + } } } TextAtom* const atom = new TextAtom(); - atom->atomText = String (text + start, i - start); + atom->atomText = String (start, numChars); atom->width = font.getStringWidthFloat (atom->getText (passwordCharacter)); - atom->numChars = (uint16) (i - start); + atom->numChars = (uint16) numChars; atoms.add (atom); } diff --git a/src/gui/components/positioning/juce_RelativePoint.cpp b/src/gui/components/positioning/juce_RelativePoint.cpp index 3458b9a592..374b6c5e81 100644 --- a/src/gui/components/positioning/juce_RelativePoint.cpp +++ b/src/gui/components/positioning/juce_RelativePoint.cpp @@ -31,13 +31,12 @@ BEGIN_JUCE_NAMESPACE namespace RelativePointHelpers { - void skipComma (const juce_wchar* const s, int& i) + inline void skipComma (String::CharPointerType& s) { - while (CharacterFunctions::isWhitespace (s[i])) - ++i; + s = s.findEndOfWhitespace(); - if (s[i] == ',') - ++i; + if (*s == ',') + ++s; } } @@ -63,10 +62,10 @@ RelativePoint::RelativePoint (const RelativeCoordinate& x_, const RelativeCoordi RelativePoint::RelativePoint (const String& s) { - int i = 0; - x = RelativeCoordinate (Expression::parse (s, i)); - RelativePointHelpers::skipComma (s, i); - y = RelativeCoordinate (Expression::parse (s, i)); + String::CharPointerType text (s.getCharPointer()); + x = RelativeCoordinate (Expression::parse (text)); + RelativePointHelpers::skipComma (text); + y = RelativeCoordinate (Expression::parse (text)); } bool RelativePoint::operator== (const RelativePoint& other) const throw() diff --git a/src/gui/components/positioning/juce_RelativeRectangle.cpp b/src/gui/components/positioning/juce_RelativeRectangle.cpp index 308a6fb1ec..4b3f7c26e8 100644 --- a/src/gui/components/positioning/juce_RelativeRectangle.cpp +++ b/src/gui/components/positioning/juce_RelativeRectangle.cpp @@ -34,13 +34,12 @@ BEGIN_JUCE_NAMESPACE //============================================================================== namespace RelativeRectangleHelpers { - inline void skipComma (const juce_wchar* const s, int& i) + inline void skipComma (String::CharPointerType& s) { - while (CharacterFunctions::isWhitespace (s[i])) - ++i; + s = s.findEndOfWhitespace(); - if (s[i] == ',') - ++i; + if (*s == ',') + ++s; } bool dependsOnSymbolsOtherThanThis (const Expression& e) @@ -95,14 +94,14 @@ RelativeRectangle::RelativeRectangle (const Rectangle& rect) RelativeRectangle::RelativeRectangle (const String& s) { - int i = 0; - left = RelativeCoordinate (Expression::parse (s, i)); - RelativeRectangleHelpers::skipComma (s, i); - top = RelativeCoordinate (Expression::parse (s, i)); - RelativeRectangleHelpers::skipComma (s, i); - right = RelativeCoordinate (Expression::parse (s, i)); - RelativeRectangleHelpers::skipComma (s, i); - bottom = RelativeCoordinate (Expression::parse (s, i)); + String::CharPointerType text (s.getCharPointer()); + left = RelativeCoordinate (Expression::parse (text)); + RelativeRectangleHelpers::skipComma (text); + top = RelativeCoordinate (Expression::parse (text)); + RelativeRectangleHelpers::skipComma (text); + right = RelativeCoordinate (Expression::parse (text)); + RelativeRectangleHelpers::skipComma (text); + bottom = RelativeCoordinate (Expression::parse (text)); } bool RelativeRectangle::operator== (const RelativeRectangle& other) const throw() diff --git a/src/gui/graphics/drawables/juce_SVGParser.cpp b/src/gui/graphics/drawables/juce_SVGParser.cpp index 8c68c87e3a..b18be17b97 100644 --- a/src/gui/graphics/drawables/juce_SVGParser.cpp +++ b/src/gui/graphics/drawables/juce_SVGParser.cpp @@ -45,10 +45,6 @@ public: { } - ~SVGState() - { - } - //============================================================================== Drawable* parseSVGElement (const XmlElement& xml) { @@ -71,12 +67,12 @@ public: if (xml.hasAttribute ("viewBox")) { - const String viewParams (xml.getStringAttribute ("viewBox")); - int i = 0; + const String viewBoxAtt (xml.getStringAttribute ("viewBox")); + String::CharPointerType viewParams (viewBoxAtt.getCharPointer()); float vx, vy, vw, vh; - if (parseCoords (viewParams, vx, vy, i, true) - && parseCoords (viewParams, vw, vh, i, true) + if (parseCoords (viewParams, vx, vy, true) + && parseCoords (viewParams, vw, vh, true) && vw > 0 && vh > 0) { @@ -200,28 +196,28 @@ private: //============================================================================== Drawable* parsePath (const XmlElement& xml) const { - const String d (xml.getStringAttribute ("d").trimStart()); + const String dAttribute (xml.getStringAttribute ("d").trimStart()); + String::CharPointerType d (dAttribute.getCharPointer()); Path path; if (getStyleAttribute (&xml, "fill-rule").trim().equalsIgnoreCase ("evenodd")) path.setUsingNonZeroWinding (false); - int index = 0; float lastX = 0, lastY = 0; float lastX2 = 0, lastY2 = 0; juce_wchar lastCommandChar = 0; bool isRelative = true; bool carryOn = true; - const String validCommandChars ("MmLlHhVvCcSsQqTtAaZz"); + const CharPointer_ASCII validCommandChars ("MmLlHhVvCcSsQqTtAaZz"); - while (d[index] != 0) + while (! d.isEmpty()) { float x, y, x2, y2, x3, y3; - if (validCommandChars.containsChar (d[index])) + if (validCommandChars.indexOf (*d) >= 0) { - lastCommandChar = d [index++]; + lastCommandChar = d.getAndAdvance(); isRelative = (lastCommandChar >= 'a' && lastCommandChar <= 'z'); } @@ -231,7 +227,7 @@ private: case 'm': case 'L': case 'l': - if (parseCoords (d, x, y, index, false)) + if (parseCoords (d, x, y, false)) { if (isRelative) { @@ -254,14 +250,14 @@ private: } else { - ++index; + ++d; } break; case 'H': case 'h': - if (parseCoord (d, x, index, false, true)) + if (parseCoord (d, x, false, true)) { if (isRelative) x += lastX; @@ -273,13 +269,13 @@ private: } else { - ++index; + ++d; } break; case 'V': case 'v': - if (parseCoord (d, y, index, false, false)) + if (parseCoord (d, y, false, false)) { if (isRelative) y += lastY; @@ -291,15 +287,15 @@ private: } else { - ++index; + ++d; } break; case 'C': case 'c': - if (parseCoords (d, x, y, index, false) - && parseCoords (d, x2, y2, index, false) - && parseCoords (d, x3, y3, index, false)) + if (parseCoords (d, x, y, false) + && parseCoords (d, x2, y2, false) + && parseCoords (d, x3, y3, false)) { if (isRelative) { @@ -320,14 +316,14 @@ private: } else { - ++index; + ++d; } break; case 'S': case 's': - if (parseCoords (d, x, y, index, false) - && parseCoords (d, x3, y3, index, false)) + if (parseCoords (d, x, y, false) + && parseCoords (d, x3, y3, false)) { if (isRelative) { @@ -348,14 +344,14 @@ private: } else { - ++index; + ++d; } break; case 'Q': case 'q': - if (parseCoords (d, x, y, index, false) - && parseCoords (d, x2, y2, index, false)) + if (parseCoords (d, x, y, false) + && parseCoords (d, x2, y2, false)) { if (isRelative) { @@ -374,13 +370,13 @@ private: } else { - ++index; + ++d; } break; case 'T': case 't': - if (parseCoords (d, x, y, index, false)) + if (parseCoords (d, x, y, false)) { if (isRelative) { @@ -399,29 +395,29 @@ private: } else { - ++index; + ++d; } break; case 'A': case 'a': - if (parseCoords (d, x, y, index, false)) + if (parseCoords (d, x, y, false)) { String num; - if (parseNextNumber (d, num, index, false)) + if (parseNextNumber (d, num, false)) { const float angle = num.getFloatValue() * (180.0f / float_Pi); - if (parseNextNumber (d, num, index, false)) + if (parseNextNumber (d, num, false)) { const bool largeArc = num.getIntValue() != 0; - if (parseNextNumber (d, num, index, false)) + if (parseNextNumber (d, num, false)) { const bool sweep = num.getIntValue() != 0; - if (parseCoords (d, x2, y2, index, false)) + if (parseCoords (d, x2, y2, false)) { if (isRelative) { @@ -458,7 +454,7 @@ private: } else { - ++index; + ++d; } break; @@ -466,9 +462,7 @@ private: case 'Z': case 'z': path.closeSubPath(); - while (CharacterFunctions::isWhitespace (d [index])) - ++index; - + d = d.findEndOfWhitespace(); break; default: @@ -561,13 +555,12 @@ private: Drawable* parsePolygon (const XmlElement& xml, const bool isPolyline) const { - const String points (xml.getStringAttribute ("points")); + const String pointsAtt (xml.getStringAttribute ("points")); + String::CharPointerType points (pointsAtt.getCharPointer()); Path path; - - int index = 0; float x, y; - if (parseCoords (points, x, y, index, true)) + if (parseCoords (points, x, y, true)) { float firstX = x; float firstY = y; @@ -575,7 +568,7 @@ private: path.startNewSubPath (x, y); - while (parseCoords (points, x, y, index, true)) + while (parseCoords (points, x, y, true)) { lastX = x; lastY = y; @@ -865,12 +858,11 @@ private: } //============================================================================== - bool parseCoord (const String& s, float& value, int& index, - const bool allowUnits, const bool isX) const + bool parseCoord (String::CharPointerType& s, float& value, const bool allowUnits, const bool isX) const { String number; - if (! parseNextNumber (s, number, index, allowUnits)) + if (! parseNextNumber (s, number, allowUnits)) { value = 0; return false; @@ -880,11 +872,10 @@ private: return true; } - bool parseCoords (const String& s, float& x, float& y, - int& index, const bool allowUnits) const + bool parseCoords (String::CharPointerType& s, float& x, float& y, const bool allowUnits) const { - return parseCoord (s, x, index, allowUnits, true) - && parseCoord (s, y, index, allowUnits, false); + return parseCoord (s, x, allowUnits, true) + && parseCoord (s, y, allowUnits, false); } float getCoordLength (const String& s, const float sizeForProportions) const @@ -917,10 +908,10 @@ private: void getCoordList (Array & coords, const String& list, const bool allowUnits, const bool isX) const { - int index = 0; + String::CharPointerType text (list.getCharPointer()); float value; - while (parseCoord (list, value, index, allowUnits, isX)) + while (parseCoord (text, value, allowUnits, isX)) coords.add (value); } @@ -1034,45 +1025,55 @@ private: } //============================================================================== - static bool parseNextNumber (const String& source, String& value, int& index, const bool allowUnits) + static bool parseNextNumber (String::CharPointerType& s, String& value, const bool allowUnits) { - const juce_wchar* const s = source; + while (s.isWhitespace() || *s == ',') + ++s; - while (CharacterFunctions::isWhitespace (s[index]) || s[index] == ',') - ++index; + String::CharPointerType start (s); + int numChars = 0; - int start = index; - - if (CharacterFunctions::isDigit (s[index]) || s[index] == '.' || s[index] == '-') - ++index; - - while (CharacterFunctions::isDigit (s[index]) || s[index] == '.') - ++index; - - if ((s[index] == 'e' || s[index] == 'E') - && (CharacterFunctions::isDigit (s[index + 1]) - || s[index + 1] == '-' - || s[index + 1] == '+')) + if (s.isDigit() || *s == '.' || *s == '-') { - index += 2; + ++numChars; + ++s; + } - while (CharacterFunctions::isDigit (s[index])) - ++index; + while (s.isDigit() || *s == '.') + { + ++numChars; + ++s; + } + + if ((*s == 'e' || *s == 'E') + && ((s + 1).isDigit() || s[1] == '-' || s[1] == '+')) + { + s += 2; + numChars += 2; + + while (s.isDigit()) + { + ++numChars; + ++s; + } } if (allowUnits) { - while (CharacterFunctions::isLetter (s[index])) - ++index; + while (s.isLetter()) + { + ++numChars; + ++s; + } } - if (index == start) + if (numChars == 0) return false; - value = String (s + start, index - start); + value = String (start, numChars); - while (CharacterFunctions::isWhitespace (s[index]) || s[index] == ',') - ++index; + while (s.isWhitespace() || *s == ',') + ++s; return true; } diff --git a/src/gui/graphics/fonts/juce_GlyphArrangement.cpp b/src/gui/graphics/fonts/juce_GlyphArrangement.cpp index 8e46df4519..d944262f90 100644 --- a/src/gui/graphics/fonts/juce_GlyphArrangement.cpp +++ b/src/gui/graphics/fonts/juce_GlyphArrangement.cpp @@ -198,7 +198,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, font.getGlyphPositions (text, newGlyphs, xOffsets); const int textLen = newGlyphs.size(); - const juce_wchar* const unicodeText = text; + String::CharPointerType t (text.getCharPointer()); for (int i = 0; i < textLen; ++i) { @@ -216,7 +216,7 @@ void GlyphArrangement::addCurtailedLineOfText (const Font& font, else { glyphs.add (new PositionedGlyph (xOffset + thisX, yOffset, nextX - thisX, - font, unicodeText[i], newGlyphs.getUnchecked(i))); + font, t.getAndAdvance(), newGlyphs.getUnchecked(i))); } } } diff --git a/src/gui/graphics/fonts/juce_TextLayout.cpp b/src/gui/graphics/fonts/juce_TextLayout.cpp index 4a7771f30b..f37b2dce65 100644 --- a/src/gui/graphics/fonts/juce_TextLayout.cpp +++ b/src/gui/graphics/fonts/juce_TextLayout.cpp @@ -140,13 +140,13 @@ bool TextLayout::isEmpty() const void TextLayout::appendText (const String& text, const Font& font) { - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); String currentString; int lastCharType = 0; for (;;) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); if (c == 0) break; @@ -175,7 +175,7 @@ void TextLayout::appendText (const String& text, const Font& font) currentString = String::charToString (c); if (c == '\r' && *t == '\n') - currentString += *t++; + currentString += t.getAndAdvance(); } else { diff --git a/src/gui/graphics/fonts/juce_Typeface.cpp b/src/gui/graphics/fonts/juce_Typeface.cpp index eb1c0c1e66..ab98ee2503 100644 --- a/src/gui/graphics/fonts/juce_Typeface.cpp +++ b/src/gui/graphics/fonts/juce_Typeface.cpp @@ -331,11 +331,11 @@ float CustomTypeface::getDescent() const float CustomTypeface::getStringWidth (const String& text) { float x = 0; - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); - while (*t != 0) + while (! t.isEmpty()) { - const GlyphInfo* const glyph = findGlyphSubstituting (*t++); + const GlyphInfo* const glyph = findGlyphSubstituting (t.getAndAdvance()); if (glyph == 0 && ! isFallbackFont) { @@ -356,11 +356,11 @@ void CustomTypeface::getGlyphPositions (const String& text, Array & resultG { xOffsets.add (0); float x = 0; - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); - while (*t != 0) + while (! t.isEmpty()) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); const GlyphInfo* const glyph = findGlyph (c, true); if (glyph == 0 && ! isFallbackFont) diff --git a/src/gui/graphics/geometry/juce_Path.cpp b/src/gui/graphics/geometry/juce_Path.cpp index 64f43f461a..9cf905c56c 100644 --- a/src/gui/graphics/geometry/juce_Path.cpp +++ b/src/gui/graphics/geometry/juce_Path.cpp @@ -43,17 +43,20 @@ namespace PathHelpers { const float ellipseAngularIncrement = 0.05f; - const String nextToken (const juce_wchar*& t) + const String nextToken (String::CharPointerType& t) { - while (CharacterFunctions::isWhitespace (*t)) + t = t.findEndOfWhitespace(); + + String::CharPointerType start (t); + int numChars = 0; + + while (! (t.isEmpty() || t.isWhitespace())) + { ++t; + ++numChars; + } - const juce_wchar* const start = t; - - while (*t != 0 && ! CharacterFunctions::isWhitespace (*t)) - ++t; - - return String (start, (int) (t - start)); + return String (start, numChars); } inline double lengthOf (float x1, float y1, float x2, float y2) throw() @@ -1453,7 +1456,7 @@ void Path::restoreFromString (const String& stringVersion) clear(); setUsingNonZeroWinding (true); - const juce_wchar* t = stringVersion; + String::CharPointerType t (stringVersion.getCharPointer()); juce_wchar marker = 'm'; int numValues = 2; float values [6]; diff --git a/src/io/files/juce_File.cpp b/src/io/files/juce_File.cpp index f98d9dde69..e072810cff 100644 --- a/src/io/files/juce_File.cpp +++ b/src/io/files/juce_File.cpp @@ -852,11 +852,8 @@ const String File::getRelativePathFrom (const File& dir) const { String thisPath (fullPath); - { - int len = thisPath.length(); - while (--len >= 0 && thisPath [len] == File::separator) - thisPath [len] = 0; - } + while (thisPath.endsWithChar (separator)) + thisPath = thisPath.dropLastCharacters (1); String dirPath (addTrailingSeparator (dir.existsAsFile() ? dir.getParentDirectory().getFullPathName() : dir.fullPath)); @@ -1012,6 +1009,9 @@ public: expect (tempFile.loadFileAsString() == "0123456789"); expect (! demoFolder.containsSubDirectories()); + expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() + File::separatorString + tempFile.getFileName()); + expectEquals (demoFolder.getParentDirectory().getRelativePathFrom (tempFile), ".." + File::separatorString + ".." + File::separatorString + demoFolder.getParentDirectory().getFileName()); + expect (demoFolder.getNumberOfChildFiles (File::findFiles) == 1); expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 1); expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 0); diff --git a/src/io/files/juce_File.h b/src/io/files/juce_File.h index 6665195f87..ed5082a294 100644 --- a/src/io/files/juce_File.h +++ b/src/io/files/juce_File.h @@ -166,7 +166,7 @@ public: /** Creates a relative path that refers to a file relatively to a given directory. - e.g. File ("/moose/foo.txt").getRelativePathFrom ("/moose/fish/haddock") + e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock")) would return "../../foo.txt". If it's not possible to navigate from one file to the other, an absolute diff --git a/src/io/streams/juce_MemoryOutputStream.cpp b/src/io/streams/juce_MemoryOutputStream.cpp index 4553831c06..26c99473af 100644 --- a/src/io/streams/juce_MemoryOutputStream.cpp +++ b/src/io/streams/juce_MemoryOutputStream.cpp @@ -131,7 +131,7 @@ int MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumB const String MemoryOutputStream::toUTF8() const { - return String (static_cast (getData()), getDataSize()); + return String::fromUTF8 (static_cast (getData()), getDataSize()); } const String MemoryOutputStream::toString() const diff --git a/src/io/streams/juce_OutputStream.cpp b/src/io/streams/juce_OutputStream.cpp index 57a5fc4ba2..41775501d6 100644 --- a/src/io/streams/juce_OutputStream.cpp +++ b/src/io/streams/juce_OutputStream.cpp @@ -180,24 +180,29 @@ void OutputStream::writeString (const String& text) write (temp, numBytes); } -void OutputStream::writeText (const String& text, const bool asUnicode, - const bool writeUnicodeHeaderBytes) +void OutputStream::writeText (const String& text, const bool asUTF16, + const bool writeUTF16ByteOrderMark) { - if (asUnicode) + if (asUTF16) { - if (writeUnicodeHeaderBytes) + if (writeUTF16ByteOrderMark) write ("\x0ff\x0fe", 2); - const juce_wchar* src = text; + String::CharPointerType src (text.getCharPointer()); bool lastCharWasReturn = false; - while (*src != 0) + for (;;) { - if (*src == L'\n' && ! lastCharWasReturn) - writeShort ((short) L'\r'); + const juce_wchar c = src.getAndAdvance(); - lastCharWasReturn = (*src == L'\r'); - writeShort ((short) *src++); + if (c == 0) + break; + + if (c == '\n' && ! lastCharWasReturn) + writeShort ((short) '\r'); + + lastCharWasReturn = (c == L'\r'); + writeShort ((short) c); } } else diff --git a/src/io/streams/juce_OutputStream.h b/src/io/streams/juce_OutputStream.h index 3f626bad2b..a405c88697 100644 --- a/src/io/streams/juce_OutputStream.h +++ b/src/io/streams/juce_OutputStream.h @@ -186,15 +186,15 @@ public: /** Writes a string of text to the stream. - It can either write it as UTF8 characters or as unicode, and - can also add unicode header bytes (0xff, 0xfe) to indicate the endianness (this - should only be done at the start of a file). + It can either write the text as UTF-8 or UTF-16, and can also add the UTF-16 byte-order-mark + bytes (0xff, 0xfe) to indicate the endianness (these should only be used at the start + of a file). The method also replaces '\\n' characters in the text with '\\r\\n'. */ virtual void writeText (const String& text, - bool asUnicode, - bool writeUnicodeHeaderBytes); + bool asUTF16, + bool writeUTF16ByteOrderMark); /** Reads data from an input stream and writes it to this stream. diff --git a/src/maths/juce_BigInteger.cpp b/src/maths/juce_BigInteger.cpp index 7b4b222d46..844f6fe4c8 100644 --- a/src/maths/juce_BigInteger.cpp +++ b/src/maths/juce_BigInteger.cpp @@ -946,7 +946,7 @@ const String BigInteger::toString (const int base, const int minimumNumCharacter void BigInteger::parseString (const String& text, const int base) { clear(); - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); if (base == 2 || base == 8 || base == 16) { @@ -954,7 +954,7 @@ void BigInteger::parseString (const String& text, const int base) for (;;) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); const int digit = CharacterFunctions::getHexDigitValue (c); if (((uint32) digit) < (uint32) base) @@ -974,7 +974,7 @@ void BigInteger::parseString (const String& text, const int base) for (;;) { - const juce_wchar c = *t++; + const juce_wchar c = t.getAndAdvance(); if (c >= '0' && c <= '9') { diff --git a/src/maths/juce_Expression.cpp b/src/maths/juce_Expression.cpp index a74b71ee25..3688500c20 100644 --- a/src/maths/juce_Expression.cpp +++ b/src/maths/juce_Expression.cpp @@ -660,29 +660,26 @@ public: { public: //============================================================================== - Parser (const String& stringToParse, int& textIndex_) - : textString (stringToParse), textIndex (textIndex_) + Parser (String::CharPointerType& stringToParse) + : text (stringToParse) { - text = textString; } const TermPtr readUpToComma() { - if (textString.isEmpty()) + if (text.isEmpty()) return new Constant (0.0, false); const TermPtr e (readExpression()); - if (e == 0 || ((! readOperator (",")) && text [textIndex] != 0)) - throw ParseError ("Syntax error: \"" + textString.substring (textIndex) + "\""); + if (e == 0 || ((! readOperator (",")) && ! text.isEmpty())) + throw ParseError ("Syntax error: \"" + String (text) + "\""); return e; } private: - const String textString; - const juce_wchar* text; - int& textIndex; + String::CharPointerType& text; //============================================================================== static inline bool isDecimalDigit (const juce_wchar c) throw() @@ -690,17 +687,11 @@ public: return c >= '0' && c <= '9'; } - void skipWhitespace (int& i) throw() - { - while (CharacterFunctions::isWhitespace (text [i])) - ++i; - } - bool readChar (const juce_wchar required) throw() { - if (text[textIndex] == required) + if (*text == required) { - ++textIndex; + ++text; return true; } @@ -709,7 +700,7 @@ public: bool readOperator (const char* ops, char* const opType = 0) throw() { - skipWhitespace (textIndex); + text = text.findEndOfWhitespace(); while (*ops != 0) { @@ -729,21 +720,26 @@ public: bool readIdentifier (String& identifier) throw() { - skipWhitespace (textIndex); - int i = textIndex; + text = text.findEndOfWhitespace(); + String::CharPointerType t (text); + int numChars = 0; - if (CharacterFunctions::isLetter (text[i]) || text[i] == '_') + if (t.isLetter() || *t == '_') { - ++i; + ++t; + ++numChars; - while (CharacterFunctions::isLetterOrDigit (text[i]) || text[i] == '_') - ++i; + while (t.isLetterOrDigit() || *t == '_') + { + ++t; + ++numChars; + } } - if (i > textIndex) + if (numChars > 0) { - identifier = String (text + textIndex, i - textIndex); - textIndex = i; + identifier = String (text, numChars); + text = t; return true; } @@ -752,71 +748,27 @@ public: Term* readNumber() throw() { - skipWhitespace (textIndex); - int i = textIndex; + text = text.findEndOfWhitespace(); + String::CharPointerType t (text); - const bool isResolutionTarget = (text[i] == '@'); + const bool isResolutionTarget = (*t == '@'); if (isResolutionTarget) { - ++i; - skipWhitespace (i); - textIndex = i; + ++t; + t = t.findEndOfWhitespace(); + text = t; } - if (text[i] == '-') + if (*t == '-') { - ++i; - skipWhitespace (i); + ++t; + t = t.findEndOfWhitespace(); } - int numDigits = 0; + if (isDecimalDigit (*t) || (*t == '.' && isDecimalDigit (t[1]))) + return new Constant (CharacterFunctions::readDoubleValue (text), isResolutionTarget); - while (isDecimalDigit (text[i])) - { - ++i; - ++numDigits; - } - - const bool hasPoint = (text[i] == '.'); - - if (hasPoint) - { - ++i; - - while (isDecimalDigit (text[i])) - { - ++i; - ++numDigits; - } - } - - if (numDigits == 0) - return 0; - - juce_wchar c = text[i]; - const bool hasExponent = (c == 'e' || c == 'E'); - - if (hasExponent) - { - ++i; - c = text[i]; - if (c == '+' || c == '-') - ++i; - - int numExpDigits = 0; - while (isDecimalDigit (text[i])) - { - ++i; - ++numExpDigits; - } - - if (numExpDigits == 0) - return 0; - } - - const int start = textIndex; - textIndex = i; - return new Constant (String (text + start, i - start).getDoubleValue(), isResolutionTarget); + return 0; } const TermPtr readExpression() @@ -1002,14 +954,14 @@ Expression& Expression::operator= (const Expression& other) Expression::Expression (const String& stringToParse) { - int i = 0; - Helpers::Parser parser (stringToParse, i); + String::CharPointerType text (stringToParse.getCharPointer()); + Helpers::Parser parser (text); term = parser.readUpToComma(); } -const Expression Expression::parse (const String& stringToParse, int& textIndexToStartFrom) +const Expression Expression::parse (String::CharPointerType& stringToParse) { - Helpers::Parser parser (stringToParse, textIndexToStartFrom); + Helpers::Parser parser (stringToParse); return Expression (parser.readUpToComma()); } diff --git a/src/maths/juce_Expression.h b/src/maths/juce_Expression.h index 4eea8dc1a6..e46f36edee 100644 --- a/src/maths/juce_Expression.h +++ b/src/maths/juce_Expression.h @@ -91,15 +91,16 @@ public: /** Returns an Expression which is a function call. */ static const Expression function (const String& functionName, const Array& parameters); - /** Returns an Expression which parses a string from a specified character index. + /** Returns an Expression which parses a string from a character pointer, and updates the pointer + to indicate where it finished. - The index value is incremented so that on return, it indicates the character that follows + The pointer is incremented so that on return, it indicates the character that follows the end of the expression that was parsed. If there's a syntax error in the string, this will throw a ParseError exception. @throws ParseError */ - static const Expression parse (const String& stringToParse, int& textIndexToStartFrom); + static const Expression parse (String::CharPointerType& stringToParse); //============================================================================== /** When evaluating an Expression object, this class is used to resolve symbols and diff --git a/src/memory/juce_MemoryBlock.cpp b/src/memory/juce_MemoryBlock.cpp index f0ab797227..d56de57281 100644 --- a/src/memory/juce_MemoryBlock.cpp +++ b/src/memory/juce_MemoryBlock.cpp @@ -336,15 +336,14 @@ const String MemoryBlock::toBase64Encoding() const const int initialLen = destString.length(); destString.preallocateStorage (initialLen + 2 + numChars); - juce_wchar* d = destString; + String::CharPointerType d (destString.getCharPointer()); d += initialLen; - *d++ = '.'; + d.write ('.'); for (size_t i = 0; i < numChars; ++i) - *d++ = encodingTable [getBitRange (i * 6, 6)]; - - *d++ = 0; + d.write (encodingTable [getBitRange (i * 6, 6)]); + d.writeNull(); return destString; } @@ -360,13 +359,14 @@ bool MemoryBlock::fromBase64Encoding (const String& s) setSize (numBytesNeeded, true); const int numChars = s.length() - startPos; - const juce_wchar* srcChars = s; + + String::CharPointerType srcChars (s.getCharPointer()); srcChars += startPos; int pos = 0; for (int i = 0; i < numChars; ++i) { - const char c = (char) srcChars[i]; + const char c = (char) srcChars.getAndAdvance(); for (int j = 0; j < 64; ++j) { diff --git a/src/native/mac/juce_mac_Fonts.mm b/src/native/mac/juce_mac_Fonts.mm index ebdb313987..55380ce9dd 100644 --- a/src/native/mac/juce_mac_Fonts.mm +++ b/src/native/mac/juce_mac_Fonts.mm @@ -195,7 +195,7 @@ public: const int length = text.length(); HeapBlock glyphs; - createGlyphsForString (text, length, glyphs); + createGlyphsForString (text.getCharPointer(), length, glyphs); float x = 0; @@ -238,7 +238,7 @@ public: const int length = text.length(); HeapBlock glyphs; - createGlyphsForString (text, length, glyphs); + createGlyphsForString (text.getCharPointer(), length, glyphs); #if SUPPORT_ONLY_10_4_FONTS HeapBlock advances (length); @@ -340,7 +340,7 @@ private: AffineTransform pathTransform; #endif - void createGlyphsForString (const juce_wchar* const text, const int length, HeapBlock & glyphs) + void createGlyphsForString (String::CharPointerType text, const int length, HeapBlock & glyphs) { #if SUPPORT_10_4_FONTS #if ! SUPPORT_ONLY_10_4_FONTS @@ -351,7 +351,7 @@ private: NSGlyph* const nsGlyphs = reinterpret_cast (glyphs.getData()); for (int i = 0; i < length; ++i) - nsGlyphs[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text[i]]; + nsGlyphs[i] = (NSGlyph) [nsFont _defaultGlyphForChar: text.getAndAdvance()]; return; } @@ -364,7 +364,7 @@ private: glyphs.malloc (length); for (int i = 0; i < length; ++i) - glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text[i]); + glyphs[i] = (CGGlyph) charToGlyphMapper->getGlyphForCharacter (text.getAndAdvance()); #endif } diff --git a/src/native/mac/juce_mac_Strings.mm b/src/native/mac/juce_mac_Strings.mm index 0e7f5cf48b..ddfd8a2f72 100644 --- a/src/native/mac/juce_mac_Strings.mm +++ b/src/native/mac/juce_mac_Strings.mm @@ -119,7 +119,7 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) { result.preallocateStorage (bytesRead / sizeof (UniChar) + 2); - CharPointer_UTF32 dest (static_cast (result)); + CharPointer_UTF32 dest (result.getCharPointer()); dest.writeAll (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData())); } diff --git a/src/native/windows/juce_win32_Messaging.cpp b/src/native/windows/juce_win32_Messaging.cpp index cb92d9af9a..12c243a904 100644 --- a/src/native/windows/juce_win32_Messaging.cpp +++ b/src/native/windows/juce_win32_Messaging.cpp @@ -233,7 +233,7 @@ void MessageManager::broadcastMessage (const String& value) COPYDATASTRUCT data; data.dwData = broadcastId; data.cbData = (localCopy.length() + 1) * sizeof (juce_wchar); - data.lpData = (void*) static_cast (localCopy); + data.lpData = (void*) localCopy.toUTF16().getAddress(); for (int i = windows.size(); --i >= 0;) { diff --git a/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp b/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp index e0cb7f44c5..bca970805b 100644 --- a/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp +++ b/src/native/windows/juce_win32_QuickTimeMovieComponent.cpp @@ -334,14 +334,7 @@ static Handle createHandleDataRef (Handle dataHandle, const char* fileName) static CFStringRef juceStringToCFString (const String& s) { - const int len = s.length(); - const juce_wchar* const t = s; - - HeapBlock temp (len + 2); - for (int i = 0; i <= len; ++i) - temp[i] = t[i]; - - return CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len); + return CFStringCreateWithCString (kCFAllocatorDefault, s.toUTF8(), kCFStringEncodingUTF8); } static bool openMovie (QTNewMoviePropertyElement* props, int prop, Movie& movie) diff --git a/src/text/juce_CharacterFunctions.h b/src/text/juce_CharacterFunctions.h index c206fa43dc..f456520234 100644 --- a/src/text/juce_CharacterFunctions.h +++ b/src/text/juce_CharacterFunctions.h @@ -96,7 +96,7 @@ public: //============================================================================== template - static double getDoubleValue (const CharPointerType& text) throw() + static double readDoubleValue (CharPointerType& text) throw() { double result[3] = { 0, 0, 0 }, accumulator[2] = { 0, 0 }; int exponentAdjustment[2] = { 0, 0 }, exponentAccumulator[2] = { -1, -1 }; @@ -105,36 +105,36 @@ public: bool isNegative = false, digitsFound = false; const int maxSignificantDigits = 15 + 2; - CharPointerType s (text.findEndOfWhitespace()); - juce_wchar c = *s; + text = text.findEndOfWhitespace(); + juce_wchar c = *text; switch (c) { case '-': isNegative = true; // fall-through.. - case '+': c = *++s; + case '+': c = *++text; } switch (c) { case 'n': case 'N': - if ((s[1] == 'a' || s[1] == 'A') && (s[2] == 'n' || s[2] == 'N')) + if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N')) return std::numeric_limits::quiet_NaN(); break; case 'i': case 'I': - if ((s[1] == 'n' || s[1] == 'N') && (s[2] == 'f' || s[2] == 'F')) + if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F')) return std::numeric_limits::infinity(); break; } for (;;) { - if (s.isDigit()) + if (text.isDigit()) { lastDigit = digit; - digit = s.getAndAdvance() - '0'; + digit = text.getAndAdvance() - '0'; digitsFound = true; if (decPointIndex != 0) @@ -155,9 +155,9 @@ public: else exponentAdjustment[0]++; - while (s.isDigit()) + while (text.isDigit()) { - ++s; + ++text; if (decPointIndex == 0) exponentAdjustment[0]++; } @@ -177,15 +177,15 @@ public: exponentAccumulator [decPointIndex]++; } } - else if (decPointIndex == 0 && *s == '.') + else if (decPointIndex == 0 && *text == '.') { - ++s; + ++text; decPointIndex = 1; if (numSignificantDigits > maxSignificantDigits) { - while (s.isDigit()) - ++s; + while (text.isDigit()) + ++text; break; } } @@ -200,19 +200,19 @@ public: if (decPointIndex != 0) result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1]; - c = *s; + c = *text; if ((c == 'e' || c == 'E') && digitsFound) { bool negativeExponent = false; - switch (*++s) + switch (*++text) { case '-': negativeExponent = true; // fall-through.. - case '+': ++s; + case '+': ++text; } - while (s.isDigit()) - exponent = (exponent * 10) + (s.getAndAdvance() - '0'); + while (text.isDigit()) + exponent = (exponent * 10) + (text.getAndAdvance() - '0'); if (negativeExponent) exponent = -exponent; @@ -225,6 +225,13 @@ public: return isNegative ? -r : r; } + template + static double getDoubleValue (const CharPointerType& text) throw() + { + CharPointerType t (text); + return readDoubleValue (t); + } + //============================================================================== template static IntType getIntValue (const CharPointerType& text) throw() diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index 54c91f21c6..b06bf11984 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -522,6 +522,12 @@ int String::length() const throw() return (int) text.length(); } +const juce_wchar String::operator[] (int index) const throw() +{ + jassert (index == 0 || isPositiveAndNotGreaterThan (index, length())); + return text [index]; +} + int String::hashCode() const throw() { const juce_wchar* t = text; @@ -1449,13 +1455,6 @@ const String String::toLowerCase() const } //============================================================================== -juce_wchar& String::operator[] (const int index) -{ - jassert (isPositiveAndNotGreaterThan (index, length())); - text = StringHolder::makeUnique (text); - return text [index]; -} - juce_wchar String::getLastCharacter() const throw() { return isEmpty() ? juce_wchar() : text [length() - 1]; @@ -1564,18 +1563,16 @@ bool String::isQuotedString() const const String String::unquoted() const { - String s (*this); + const int len = length(); - if (s.text[0] == '"' || s.text[0] == '\'') - s = s.substring (1); + if (len == 0) + return empty; - const int lastCharIndex = s.length() - 1; + const juce_wchar lastChar = text [len - 1]; + const int dropAtStart = (*text == '"' || *text == '\'') ? 1 : 0; + const int dropAtEnd = (lastChar == '"' || lastChar == '\'') ? 1 : 0; - if (lastCharIndex >= 0 - && (s [lastCharIndex] == '"' || s[lastCharIndex] == '\'')) - s [lastCharIndex] = 0; - - return s; + return substring (dropAtStart, len - dropAtEnd); } const String String::quoted (const juce_wchar quoteCharacter) const @@ -1626,15 +1623,12 @@ const String String::trimStart() const if (isEmpty()) return empty; - CharPointerType t (text); - - while (t.isWhitespace()) - ++t; + CharPointerType t (text.findEndOfWhitespace()); if (t == text) return *this; - return String (t.getAddress()); + return String (t); } const String String::trimEnd() const @@ -2011,20 +2005,20 @@ const String String::createStringFromData (const void* const data_, const int si result.preallocateStorage (numChars + 2); const uint16* const src = (const uint16*) (data + 2); - juce_wchar* const dst = const_cast (static_cast (result)); + CharPointerType dst (result.getCharPointer()); if (bigEndian) { for (int i = 0; i < numChars; ++i) - dst[i] = (juce_wchar) ByteOrder::swapIfLittleEndian (src[i]); + dst.write ((juce_wchar) ByteOrder::swapIfLittleEndian (src[i])); } else { for (int i = 0; i < numChars; ++i) - dst[i] = (juce_wchar) ByteOrder::swapIfBigEndian (src[i]); + dst.write ((juce_wchar) ByteOrder::swapIfBigEndian (src[i])); } - dst [numChars] = 0; + dst.writeNull(); return result; } else diff --git a/src/text/juce_String.h b/src/text/juce_String.h index 1cef9b0822..00a06ac02f 100644 --- a/src/text/juce_String.h +++ b/src/text/juce_String.h @@ -550,16 +550,7 @@ public: No checks are made to see if the index is within a valid range, so be careful! */ - inline const juce_wchar& operator[] (int index) const throw() { jassert (isPositiveAndNotGreaterThan (index, length())); return text [index]; } - - /** Returns a character from the string such that it can also be altered. - - This can be used as a way of easily changing characters in the string. - - Note that the index passed-in is not checked to see whether it's in-range, so - be careful when using this. - */ - juce_wchar& operator[] (int index); + const juce_wchar operator[] (int index) const throw(); /** Returns the final character of the string. @@ -1011,16 +1002,7 @@ public: that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ - inline operator const juce_wchar*() const throw() { return text.getAddress(); } - - //============================================================================== - /** Returns a unicode version of this string. - - Because it returns a reference to the string's internal data, the pointer - that is returned must not be stored anywhere, as it can become invalid whenever - any string methods (even some const ones!) are called. - */ - inline operator juce_wchar*() throw() { return text.getAddress(); } + inline operator const juce_wchar*() const throw() { return toUTF32().getAddress(); } //============================================================================== /** Returns the character pointer currently being used to store this string. diff --git a/src/text/juce_StringArray.cpp b/src/text/juce_StringArray.cpp index 1fee7b63d6..9ccaacc5f0 100644 --- a/src/text/juce_StringArray.cpp +++ b/src/text/juce_StringArray.cpp @@ -348,12 +348,15 @@ int StringArray::addTokens (const String& text, const String& breakCharacters, c { bool insideQuotes = false; juce_wchar currentQuoteChar = 0; - int i = 0; - int tokenStart = 0; + + String::CharPointerType t (text.getCharPointer()); + String::CharPointerType tokenStart (t); + int numChars = 0; for (;;) { - const juce_wchar c = text[i]; + const juce_wchar c = t.getAndAdvance(); + ++numChars; const bool isBreak = (c == 0) || ((! insideQuotes) && breakCharacters.containsChar (c)); @@ -377,16 +380,14 @@ int StringArray::addTokens (const String& text, const String& breakCharacters, c } else { - add (String (static_cast (text) + tokenStart, i - tokenStart)); - + add (String (tokenStart, numChars - 1)); ++num; - tokenStart = i + 1; + tokenStart = t; + numChars = 0; } if (c == 0) break; - - ++i; } } @@ -396,41 +397,39 @@ int StringArray::addTokens (const String& text, const String& breakCharacters, c int StringArray::addLines (const String& sourceText) { int numLines = 0; - const juce_wchar* text = sourceText; + String::CharPointerType text (sourceText.getCharPointer()); + bool finished = text.isEmpty(); - while (*text != 0) + while (! finished) { - const juce_wchar* const startOfLine = text; + String::CharPointerType startOfLine (text); + int numChars = 0; - while (*text != 0) + for (;;) { - if (*text == '\r') + const juce_wchar c = text.getAndAdvance(); + + if (c == 0) + { + finished = true; + break; + } + + if (c == '\n') + break; + + if (c == '\r') { - ++text; if (*text == '\n') ++text; break; } - if (*text == '\n') - { - ++text; - break; - } - - ++text; + ++numChars; } - const juce_wchar* endOfLine = text; - if (endOfLine > startOfLine && (*(endOfLine - 1) == '\r' || *(endOfLine - 1) == '\n')) - --endOfLine; - - if (endOfLine > startOfLine && (*(endOfLine - 1) == '\r' || *(endOfLine - 1) == '\n')) - --endOfLine; - - add (String (startOfLine, jmax (0, (int) (endOfLine - startOfLine)))); - + add (String (startOfLine, numChars)); ++numLines; } @@ -460,15 +459,15 @@ void StringArray::removeDuplicates (const bool ignoreCase) void StringArray::appendNumbersToDuplicates (const bool ignoreCase, const bool appendNumberToFirstInstance, - const juce_wchar* preNumberString, - const juce_wchar* postNumberString) + CharPointer_UTF8 preNumberString, + CharPointer_UTF8 postNumberString) { - String defaultPre (" ("), defaultPost (")"); // (these aren't literals because of non-unicode literals on Android) + CharPointer_UTF8 defaultPre (" ("), defaultPost (")"); - if (preNumberString == 0) + if (preNumberString.getAddress() == 0) preNumberString = defaultPre; - if (postNumberString == 0) + if (postNumberString.getAddress() == 0) postNumberString = defaultPost; for (int i = 0; i < size() - 1; ++i) @@ -484,13 +483,13 @@ void StringArray::appendNumbersToDuplicates (const bool ignoreCase, int number = 0; if (appendNumberToFirstInstance) - s = original + preNumberString + String (++number) + postNumberString; + s = original + String (preNumberString) + String (++number) + String (postNumberString); else ++number; while (nextIndex >= 0) { - set (nextIndex, (*this)[nextIndex] + preNumberString + String (++number) + postNumberString); + set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString)); nextIndex = indexOf (original, ignoreCase, nextIndex + 1); } } diff --git a/src/text/juce_StringArray.h b/src/text/juce_StringArray.h index f9177a7e93..415049f6c2 100644 --- a/src/text/juce_StringArray.h +++ b/src/text/juce_StringArray.h @@ -292,8 +292,8 @@ public: */ void appendNumbersToDuplicates (bool ignoreCaseWhenComparing, bool appendNumberToFirstInstance, - const juce_wchar* preNumberString = 0, - const juce_wchar* postNumberString = 0); + CharPointer_UTF8 preNumberString = CharPointer_UTF8 (0), + CharPointer_UTF8 postNumberString = CharPointer_UTF8 (0)); //============================================================================== /** Joins the strings in the array together into one string. diff --git a/src/text/juce_StringPool.cpp b/src/text/juce_StringPool.cpp index 4c15b48fc6..9b3871e1f3 100644 --- a/src/text/juce_StringPool.cpp +++ b/src/text/juce_StringPool.cpp @@ -37,7 +37,7 @@ StringPool::~StringPool() {} namespace StringPoolHelpers { template - const juce_wchar* getPooledStringFromArray (Array& strings, StringType newString) + const String::CharPointerType getPooledStringFromArray (Array& strings, StringType newString) { int start = 0; int end = strings.size(); @@ -48,14 +48,14 @@ namespace StringPoolHelpers { jassert (start <= end); strings.insert (start, newString); - return strings.getReference (start); + return strings.getReference (start).getCharPointer(); } else { const String& startString = strings.getReference (start); if (startString == newString) - return startString; + return startString.getCharPointer(); const int halfway = (start + end) >> 1; @@ -65,13 +65,13 @@ namespace StringPoolHelpers ++start; strings.insert (start, newString); - return strings.getReference (start); + return strings.getReference (start).getCharPointer(); } const int comp = strings.getReference (halfway).compare (newString); if (comp == 0) - return strings.getReference (halfway); + return strings.getReference (halfway).getCharPointer(); else if (comp < 0) start = halfway; else @@ -81,26 +81,26 @@ namespace StringPoolHelpers } } -const juce_wchar* StringPool::getPooledString (const String& s) +const String::CharPointerType StringPool::getPooledString (const String& s) { if (s.isEmpty()) - return String::empty; + return String::empty.getCharPointer(); return StringPoolHelpers::getPooledStringFromArray (strings, s); } -const juce_wchar* StringPool::getPooledString (const char* const s) +const String::CharPointerType StringPool::getPooledString (const char* const s) { if (s == 0 || *s == 0) - return String::empty; + return String::empty.getCharPointer(); return StringPoolHelpers::getPooledStringFromArray (strings, s); } -const juce_wchar* StringPool::getPooledString (const juce_wchar* const s) +const String::CharPointerType StringPool::getPooledString (const juce_wchar* const s) { if (s == 0 || *s == 0) - return String::empty; + return String::empty.getCharPointer(); return StringPoolHelpers::getPooledStringFromArray (strings, s); } @@ -112,7 +112,7 @@ int StringPool::size() const throw() const juce_wchar* StringPool::operator[] (const int index) const throw() { - return strings [index]; + return strings [index].getCharPointer(); } END_JUCE_NAMESPACE diff --git a/src/text/juce_StringPool.h b/src/text/juce_StringPool.h index 9bd90d4e82..c1c275d33c 100644 --- a/src/text/juce_StringPool.h +++ b/src/text/juce_StringPool.h @@ -58,7 +58,7 @@ public: The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ - const juce_wchar* getPooledString (const String& original); + const String::CharPointerType getPooledString (const String& original); /** Returns a pointer to a copy of the string that is passed in. @@ -66,7 +66,7 @@ public: The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ - const juce_wchar* getPooledString (const char* original); + const String::CharPointerType getPooledString (const char* original); /** Returns a pointer to a copy of the string that is passed in. @@ -74,7 +74,7 @@ public: The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ - const juce_wchar* getPooledString (const juce_wchar* original); + const String::CharPointerType getPooledString (const juce_wchar* original); //============================================================================== /** Returns the number of strings in the pool. */ diff --git a/src/text/juce_XmlElement.cpp b/src/text/juce_XmlElement.cpp index 122cca5a9e..c65ed739b7 100644 --- a/src/text/juce_XmlElement.cpp +++ b/src/text/juce_XmlElement.cpp @@ -47,8 +47,8 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const String& name_, const Strin { #if JUCE_DEBUG // this checks whether the attribute name string contains any illegal characters.. - for (const juce_wchar* t = name; *t != 0; ++t) - jassert (CharacterFunctions::isLetterOrDigit (*t) || *t == '_' || *t == '-' || *t == ':'); + for (String::CharPointerType t (name.getCharPointer()); ! t.isEmpty(); ++t) + jassert (t.isLetterOrDigit() || *t == '_' || *t == '-' || *t == ':'); #endif } @@ -155,16 +155,16 @@ namespace XmlOutputFunctions void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, const bool changeNewLines) { - const juce_wchar* t = text; + String::CharPointerType t (text.getCharPointer()); for (;;) { - const juce_wchar character = *t++; + const uint32 character = (uint32) t.getAndAdvance(); if (character == 0) break; - if (isLegalXmlChar ((uint32) character)) + if (isLegalXmlChar (character)) { outputStream << (char) character; } @@ -186,7 +186,7 @@ namespace XmlOutputFunctions } // Note: deliberate fall-through here! default: - outputStream << "&#" << ((int) (unsigned int) character) << ';'; + outputStream << "&#" << ((int) character) << ';'; break; } }