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; } }