diff --git a/src/audio/plugins/juce_PluginListComponent.cpp b/src/audio/plugins/juce_PluginListComponent.cpp index c1e817d109..59bc9837e0 100644 --- a/src/audio/plugins/juce_PluginListComponent.cpp +++ b/src/audio/plugins/juce_PluginListComponent.cpp @@ -131,56 +131,38 @@ void PluginListComponent::deleteKeyPressed (int lastRowSelected) list.removeType (lastRowSelected); } -void PluginListComponent::buttonClicked (Button* button) +void PluginListComponent::optionsMenuCallback (int result) { - if (button == &optionsButton) + switch (result) { - PopupMenu menu; - menu.addItem (1, TRANS("Clear list")); - menu.addItem (5, TRANS("Remove selected plugin from list"), listBox.getNumSelectedRows() > 0); - menu.addItem (6, TRANS("Show folder containing selected plugin"), listBox.getNumSelectedRows() > 0); - menu.addItem (7, TRANS("Remove any plugins whose files no longer exist")); - menu.addSeparator(); - menu.addItem (2, TRANS("Sort alphabetically")); - menu.addItem (3, TRANS("Sort by category")); - menu.addItem (4, TRANS("Sort by manufacturer")); - menu.addSeparator(); - - for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) - { - AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); - - if (format->getDefaultLocationsToSearch().getNumPaths() > 0) - menu.addItem (10 + i, "Scan for new or updated " + format->getName() + " plugins..."); - } - - const int r = menu.showMenu (PopupMenu::Options().withTargetComponent (&optionsButton)); - - if (r == 1) - { + case 1: list.clear(); - } - else if (r == 2) - { + break; + + case 2: list.sort (KnownPluginList::sortAlphabetically); - } - else if (r == 3) - { + break; + + case 3: list.sort (KnownPluginList::sortByCategory); - } - else if (r == 4) - { + break; + + case 4: list.sort (KnownPluginList::sortByManufacturer); - } - else if (r == 5) + break; + + case 5: { const SparseSet selected (listBox.getSelectedRows()); for (int i = list.getNumTypes(); --i >= 0;) if (selected.contains (i)) list.removeType (i); + + break; } - else if (r == 6) + + case 6: { const PluginDescription* const desc = list.getType (listBox.getSelectedRow()); @@ -189,22 +171,59 @@ void PluginListComponent::buttonClicked (Button* button) if (File (desc->fileOrIdentifier).existsAsFile()) File (desc->fileOrIdentifier).getParentDirectory().startAsProcess(); } + + break; } - else if (r == 7) - { + + case 7: for (int i = list.getNumTypes(); --i >= 0;) - { if (! AudioPluginFormatManager::getInstance()->doesPluginStillExist (*list.getType (i))) - { list.removeType (i); - } + + break; + + default: + if (result != 0) + { + typeToScan = result - 10; + startTimer (1); } - } - else if (r != 0) + + break; + } +} + +void PluginListComponent::optionsMenuStaticCallback (int result, PluginListComponent* pluginList) +{ + if (pluginList != 0) + pluginList->optionsMenuCallback (result); +} + +void PluginListComponent::buttonClicked (Button* button) +{ + if (button == &optionsButton) + { + PopupMenu menu; + menu.addItem (1, TRANS("Clear list")); + menu.addItem (5, TRANS("Remove selected plugin from list"), listBox.getNumSelectedRows() > 0); + menu.addItem (6, TRANS("Show folder containing selected plugin"), listBox.getNumSelectedRows() > 0); + menu.addItem (7, TRANS("Remove any plugins whose files no longer exist")); + menu.addSeparator(); + menu.addItem (2, TRANS("Sort alphabetically")); + menu.addItem (3, TRANS("Sort by category")); + menu.addItem (4, TRANS("Sort by manufacturer")); + menu.addSeparator(); + + for (int i = 0; i < AudioPluginFormatManager::getInstance()->getNumFormats(); ++i) { - typeToScan = r - 10; - startTimer (1); + AudioPluginFormat* const format = AudioPluginFormatManager::getInstance()->getFormat (i); + + if (format->getDefaultLocationsToSearch().getNumPaths() > 0) + menu.addItem (10 + i, "Scan for new or updated " + format->getName() + " plugins..."); } + + menu.showMenuAsync (PopupMenu::Options().withTargetComponent (&optionsButton), + ModalCallbackFunction::forComponent (optionsMenuStaticCallback, this)); } } diff --git a/src/audio/plugins/juce_PluginListComponent.h b/src/audio/plugins/juce_PluginListComponent.h index 03f6335af9..22bb437734 100644 --- a/src/audio/plugins/juce_PluginListComponent.h +++ b/src/audio/plugins/juce_PluginListComponent.h @@ -90,6 +90,8 @@ private: int typeToScan; void scanFor (AudioPluginFormat* format); + static void optionsMenuStaticCallback (int result, PluginListComponent*); + void optionsMenuCallback (int result); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent); }; diff --git a/src/containers/juce_Variant.cpp b/src/containers/juce_Variant.cpp index e6aa735e19..ce5753ada2 100644 --- a/src/containers/juce_Variant.cpp +++ b/src/containers/juce_Variant.cpp @@ -31,6 +31,15 @@ BEGIN_JUCE_NAMESPACE #include "juce_DynamicObject.h" #include "../io/streams/juce_MemoryOutputStream.h" +enum VariantStreamMarkers +{ + varMarker_Int = 1, + varMarker_BoolTrue = 2, + varMarker_BoolFalse = 3, + varMarker_Double = 4, + varMarker_String = 5, + varMarker_Int64 = 6 +}; //============================================================================== class var::VariantType @@ -40,6 +49,7 @@ public: virtual ~VariantType() {} virtual int toInt (const ValueUnion&) const { return 0; } + virtual int64 toInt64 (const ValueUnion&) const { return 0; } virtual double toDouble (const ValueUnion&) const { return 0; } virtual const String toString (const ValueUnion&) const { return String::empty; } virtual bool toBool (const ValueUnion&) const { return false; } @@ -47,6 +57,7 @@ public: virtual bool isVoid() const throw() { return false; } virtual bool isInt() const throw() { return false; } + virtual bool isInt64() const throw() { return false; } virtual bool isBool() const throw() { return false; } virtual bool isDouble() const throw() { return false; } virtual bool isString() const throw() { return false; } @@ -79,6 +90,7 @@ public: static const VariantType_Int instance; int toInt (const ValueUnion& data) const { return data.intValue; }; + int64 toInt64 (const ValueUnion& data) const { return (int64) data.intValue; }; double toDouble (const ValueUnion& data) const { return (double) data.intValue; } const String toString (const ValueUnion& data) const { return String (data.intValue); } bool toBool (const ValueUnion& data) const { return data.intValue != 0; } @@ -92,11 +104,38 @@ public: void writeToStream (const ValueUnion& data, OutputStream& output) const { output.writeCompressedInt (5); - output.writeByte (1); + output.writeByte (varMarker_Int); output.writeInt (data.intValue); } }; +//============================================================================== +class var::VariantType_Int64 : public var::VariantType +{ +public: + VariantType_Int64() {} + static const VariantType_Int64 instance; + + int toInt (const ValueUnion& data) const { return (int) data.int64Value; }; + int64 toInt64 (const ValueUnion& data) const { return data.int64Value; }; + double toDouble (const ValueUnion& data) const { return (double) data.int64Value; } + const String toString (const ValueUnion& data) const { return String (data.int64Value); } + bool toBool (const ValueUnion& data) const { return data.int64Value != 0; } + bool isInt64() const throw() { return true; } + + bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const throw() + { + return otherType.toInt64 (otherData) == data.int64Value; + } + + void writeToStream (const ValueUnion& data, OutputStream& output) const + { + output.writeCompressedInt (9); + output.writeByte (varMarker_Int64); + output.writeInt64 (data.int64Value); + } +}; + //============================================================================== class var::VariantType_Double : public var::VariantType { @@ -105,6 +144,7 @@ public: static const VariantType_Double instance; int toInt (const ValueUnion& data) const { return (int) data.doubleValue; }; + int64 toInt64 (const ValueUnion& data) const { return (int64) data.doubleValue; }; double toDouble (const ValueUnion& data) const { return data.doubleValue; } const String toString (const ValueUnion& data) const { return String (data.doubleValue); } bool toBool (const ValueUnion& data) const { return data.doubleValue != 0; } @@ -118,7 +158,7 @@ public: void writeToStream (const ValueUnion& data, OutputStream& output) const { output.writeCompressedInt (9); - output.writeByte (4); + output.writeByte (varMarker_Double); output.writeDouble (data.doubleValue); } }; @@ -131,6 +171,7 @@ public: static const VariantType_Bool instance; int toInt (const ValueUnion& data) const { return data.boolValue ? 1 : 0; }; + int64 toInt64 (const ValueUnion& data) const { return data.boolValue ? 1 : 0; }; double toDouble (const ValueUnion& data) const { return data.boolValue ? 1.0 : 0.0; } const String toString (const ValueUnion& data) const { return String::charToString (data.boolValue ? '1' : '0'); } bool toBool (const ValueUnion& data) const { return data.boolValue; } @@ -144,7 +185,7 @@ public: void writeToStream (const ValueUnion& data, OutputStream& output) const { output.writeCompressedInt (1); - output.writeByte (data.boolValue ? 2 : 3); + output.writeByte (data.boolValue ? varMarker_BoolTrue : varMarker_BoolFalse); } }; @@ -159,6 +200,7 @@ public: void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.stringValue = new String (*source.stringValue); } int toInt (const ValueUnion& data) const { return data.stringValue->getIntValue(); }; + int64 toInt64 (const ValueUnion& data) const { return data.stringValue->getLargeIntValue(); }; double toDouble (const ValueUnion& data) const { return data.stringValue->getDoubleValue(); } const String toString (const ValueUnion& data) const { return *data.stringValue; } bool toBool (const ValueUnion& data) const { return data.stringValue->getIntValue() != 0 @@ -175,7 +217,7 @@ public: { const int len = data.stringValue->getNumBytesAsUTF8() + 1; output.writeCompressedInt (len + 1); - output.writeByte (5); + output.writeByte (varMarker_String); HeapBlock temp (len); data.stringValue->copyToUTF8 (temp, len); output.write (temp, len); @@ -235,6 +277,7 @@ public: //============================================================================== const var::VariantType_Void var::VariantType_Void::instance; const var::VariantType_Int var::VariantType_Int::instance; +const var::VariantType_Int64 var::VariantType_Int64::instance; const var::VariantType_Bool var::VariantType_Bool::instance; const var::VariantType_Double var::VariantType_Double::instance; const var::VariantType_String var::VariantType_String::instance; @@ -265,6 +308,11 @@ var::var (const int value_) throw() : type (&VariantType_Int::instance) value.intValue = value_; } +var::var (const int64 value_) throw() : type (&VariantType_Int64::instance) +{ + value.intValue = value_; +} + var::var (const bool value_) throw() : type (&VariantType_Bool::instance) { value.boolValue = value_; @@ -306,6 +354,7 @@ var::var (MethodFunction method_) throw() : type (&VariantType_Method::instance //============================================================================== bool var::isVoid() const throw() { return type->isVoid(); } bool var::isInt() const throw() { return type->isInt(); } +bool var::isInt64() const throw() { return type->isInt64(); } bool var::isBool() const throw() { return type->isBool(); } bool var::isDouble() const throw() { return type->isDouble(); } bool var::isString() const throw() { return type->isString(); } @@ -313,6 +362,7 @@ bool var::isObject() const throw() { return type->isObject(); } bool var::isMethod() const throw() { return type->isMethod(); } var::operator int() const { return type->toInt (value); } +var::operator int64() const { return type->toInt64 (value); } var::operator bool() const { return type->toBool (value); } var::operator float() const { return (float) type->toDouble (value); } var::operator double() const { return type->toDouble (value); } @@ -329,6 +379,7 @@ void var::swapWith (var& other) throw() var& var::operator= (const var& newValue) { type->cleanUp (value); type = newValue.type; type->createCopy (value, newValue.value); return *this; } var& var::operator= (int newValue) { var v (newValue); swapWith (v); return *this; } +var& var::operator= (int64 newValue) { var v (newValue); swapWith (v); return *this; } var& var::operator= (bool newValue) { var v (newValue); swapWith (v); return *this; } var& var::operator= (double newValue) { var v (newValue); swapWith (v); return *this; } var& var::operator= (const char* newValue) { var v (newValue); swapWith (v); return *this; } @@ -367,11 +418,12 @@ const var var::readFromStream (InputStream& input) { switch (input.readByte()) { - case 1: return var (input.readInt()); - case 2: return var (true); - case 3: return var (false); - case 4: return var (input.readDouble()); - case 5: + case varMarker_Int: return var (input.readInt()); + case varMarker_Int64: return var (input.readInt64()); + case varMarker_BoolTrue: return var (true); + case varMarker_BoolFalse: return var (false); + case varMarker_Double: return var (input.readDouble()); + case varMarker_String: { MemoryOutputStream mo; mo.writeFromInputStream (input, numBytes - 1); diff --git a/src/containers/juce_Variant.h b/src/containers/juce_Variant.h index f9ac0c946e..52b7e35c45 100644 --- a/src/containers/juce_Variant.h +++ b/src/containers/juce_Variant.h @@ -63,6 +63,7 @@ public: var (const var& valueToCopy); var (int value) throw(); + var (int64 value) throw(); var (bool value) throw(); var (double value) throw(); var (const char* value); @@ -73,6 +74,7 @@ public: var& operator= (const var& valueToCopy); var& operator= (int value); + var& operator= (int64 value); var& operator= (bool value); var& operator= (double value); var& operator= (const char* value); @@ -84,6 +86,7 @@ public: void swapWith (var& other) throw(); operator int() const; + operator int64() const; operator bool() const; operator float() const; operator double() const; @@ -93,6 +96,7 @@ public: bool isVoid() const throw(); bool isInt() const throw(); + bool isInt64() const throw(); bool isBool() const throw(); bool isDouble() const throw(); bool isString() const throw(); @@ -152,6 +156,8 @@ private: friend class VariantType_Void; class VariantType_Int; friend class VariantType_Int; + class VariantType_Int64; + friend class VariantType_Int64; class VariantType_Double; friend class VariantType_Double; class VariantType_Float; @@ -168,6 +174,7 @@ private: union ValueUnion { int intValue; + int64 int64Value; bool boolValue; double doubleValue; String* stringValue; diff --git a/src/native/mac/juce_mac_Strings.mm b/src/native/mac/juce_mac_Strings.mm index ddfd8a2f72..e16ff0600b 100644 --- a/src/native/mac/juce_mac_Strings.mm +++ b/src/native/mac/juce_mac_Strings.mm @@ -117,10 +117,7 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) bytesNeeded, &bytesRead, &outputBufferSize, tempOut) == noErr) { - result.preallocateStorage (bytesRead / sizeof (UniChar) + 2); - - CharPointer_UTF32 dest (result.getCharPointer()); - dest.writeAll (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData())); + result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData())); } DisposeUnicodeToTextInfo (&conversionInfo); diff --git a/src/text/juce_CharPointer_ASCII.h b/src/text/juce_CharPointer_ASCII.h index 569bd11c45..627a15d505 100644 --- a/src/text/juce_CharPointer_ASCII.h +++ b/src/text/juce_CharPointer_ASCII.h @@ -64,16 +64,12 @@ public: } /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator== (const CharPointer_ASCII& other) const throw() - { - return data == other.data; - } - - /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator!= (const CharPointer_ASCII& other) const throw() - { - return data == other.data; - } + inline bool operator== (const CharPointer_ASCII& other) const throw() { return data == other.data; } + inline bool operator!= (const CharPointer_ASCII& other) const throw() { return data != other.data; } + inline bool operator<= (const CharPointer_ASCII& other) const throw() { return data <= other.data; } + inline bool operator< (const CharPointer_ASCII& other) const throw() { return data < other.data; } + inline bool operator>= (const CharPointer_ASCII& other) const throw() { return data >= other.data; } + inline bool operator> (const CharPointer_ASCII& other) const throw() { return data > other.data; } /** Returns the address that this pointer is pointing to. */ inline CharType* getAddress() const throw() { return data; } @@ -171,6 +167,12 @@ public: return CharacterFunctions::lengthUpTo (*this, maxCharsToCount); } + /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */ + size_t lengthUpTo (const CharPointer_ASCII& end) const throw() + { + return CharacterFunctions::lengthUpTo (*this, end); + } + /** Returns the number of bytes that are used to represent this string. This includes the terminating null character. */ diff --git a/src/text/juce_CharPointer_UTF16.h b/src/text/juce_CharPointer_UTF16.h index 3b82c2cb64..17d00d5556 100644 --- a/src/text/juce_CharPointer_UTF16.h +++ b/src/text/juce_CharPointer_UTF16.h @@ -65,16 +65,12 @@ public: } /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator== (const CharPointer_UTF16& other) const throw() - { - return data == other.data; - } - - /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator!= (const CharPointer_UTF16& other) const throw() - { - return data == other.data; - } + inline bool operator== (const CharPointer_UTF16& other) const throw() { return data == other.data; } + inline bool operator!= (const CharPointer_UTF16& other) const throw() { return data != other.data; } + inline bool operator<= (const CharPointer_UTF16& other) const throw() { return data <= other.data; } + inline bool operator< (const CharPointer_UTF16& other) const throw() { return data < other.data; } + inline bool operator>= (const CharPointer_UTF16& other) const throw() { return data >= other.data; } + inline bool operator> (const CharPointer_UTF16& other) const throw() { return data > other.data; } /** Returns the address that this pointer is pointing to. */ inline CharType* getAddress() const throw() { return data; } @@ -203,6 +199,12 @@ public: return CharacterFunctions::lengthUpTo (*this, maxCharsToCount); } + /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */ + size_t lengthUpTo (const CharPointer_UTF16& end) const throw() + { + return CharacterFunctions::lengthUpTo (*this, end); + } + /** Returns the number of bytes that are used to represent this string. This includes the terminating null character. */ diff --git a/src/text/juce_CharPointer_UTF32.h b/src/text/juce_CharPointer_UTF32.h index ca02c277a2..ed928266a3 100644 --- a/src/text/juce_CharPointer_UTF32.h +++ b/src/text/juce_CharPointer_UTF32.h @@ -61,16 +61,12 @@ public: } /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator== (const CharPointer_UTF32& other) const throw() - { - return data == other.data; - } - - /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator!= (const CharPointer_UTF32& other) const throw() - { - return data == other.data; - } + inline bool operator== (const CharPointer_UTF32& other) const throw() { return data == other.data; } + inline bool operator!= (const CharPointer_UTF32& other) const throw() { return data != other.data; } + inline bool operator<= (const CharPointer_UTF32& other) const throw() { return data <= other.data; } + inline bool operator< (const CharPointer_UTF32& other) const throw() { return data < other.data; } + inline bool operator>= (const CharPointer_UTF32& other) const throw() { return data >= other.data; } + inline bool operator> (const CharPointer_UTF32& other) const throw() { return data > other.data; } /** Returns the address that this pointer is pointing to. */ inline CharType* getAddress() const throw() { return data; } @@ -175,6 +171,12 @@ public: return CharacterFunctions::lengthUpTo (*this, maxCharsToCount); } + /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */ + size_t lengthUpTo (const CharPointer_UTF32& end) const throw() + { + return CharacterFunctions::lengthUpTo (*this, end); + } + /** Returns the number of bytes that are used to represent this string. This includes the terminating null character. */ diff --git a/src/text/juce_CharPointer_UTF8.h b/src/text/juce_CharPointer_UTF8.h index 05f926d490..7ad4d80c77 100644 --- a/src/text/juce_CharPointer_UTF8.h +++ b/src/text/juce_CharPointer_UTF8.h @@ -60,16 +60,12 @@ public: } /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator== (const CharPointer_UTF8& other) const throw() - { - return data == other.data; - } - - /** This is a pointer comparison, it doesn't compare the actual text. */ - inline bool operator!= (const CharPointer_UTF8& other) const throw() - { - return data == other.data; - } + inline bool operator== (const CharPointer_UTF8& other) const throw() { return data == other.data; } + inline bool operator!= (const CharPointer_UTF8& other) const throw() { return data != other.data; } + inline bool operator<= (const CharPointer_UTF8& other) const throw() { return data <= other.data; } + inline bool operator< (const CharPointer_UTF8& other) const throw() { return data < other.data; } + inline bool operator>= (const CharPointer_UTF8& other) const throw() { return data >= other.data; } + inline bool operator> (const CharPointer_UTF8& other) const throw() { return data > other.data; } /** Returns the address that this pointer is pointing to. */ inline CharType* getAddress() const throw() { return data; } @@ -243,6 +239,12 @@ public: return CharacterFunctions::lengthUpTo (*this, maxCharsToCount); } + /** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */ + size_t lengthUpTo (const CharPointer_UTF8& end) const throw() + { + return CharacterFunctions::lengthUpTo (*this, end); + } + /** Returns the number of bytes that are used to represent this string. This includes the terminating null character. */ diff --git a/src/text/juce_CharacterFunctions.h b/src/text/juce_CharacterFunctions.h index f713fc12e4..d036be532a 100644 --- a/src/text/juce_CharacterFunctions.h +++ b/src/text/juce_CharacterFunctions.h @@ -272,17 +272,26 @@ public: //============================================================================== template - static size_t lengthUpTo (const CharPointerType& text, const size_t maxCharsToCount) throw() + static size_t lengthUpTo (CharPointerType text, const size_t maxCharsToCount) throw() { size_t len = 0; - CharPointerType t (text); - while (len < maxCharsToCount && t.getAndAdvance() != 0) + while (len < maxCharsToCount && text.getAndAdvance() != 0) ++len; return len; } + template + static size_t lengthUpTo (CharPointerType start, const CharPointerType& end) throw() + { + size_t len = 0; + + while (start < end && start.getAndAdvance() != 0) + ++len; + + return len; + } template static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) throw() diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index 2f37ff5913..16004ac118 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -100,6 +100,21 @@ public: return dest; } + template + static const CharPointerType createFromCharPointer (const CharPointer& start, const CharPointer& end) + { + if (start.getAddress() == 0 || start.isEmpty()) + return getEmpty(); + + size_t numChars = start.lengthUpTo (end); + if (numChars == 0) + return getEmpty(); + + const CharPointerType dest (createUninitialised (numChars)); + CharPointerType (dest).writeWithCharLimit (start, (int) (numChars + 1)); + return dest; + } + static CharPointerType createFromFixedLength (const juce_wchar* const src, const size_t numChars) { CharPointerType dest (createUninitialised (numChars)); @@ -325,6 +340,11 @@ String::String (const CharPointer_UTF32& t, const size_t maxChars) { } +String::String (const CharPointer_UTF32& start, const CharPointer_UTF32& end) + : text (StringHolder::createFromCharPointer (start, end)) +{ +} + String::String (const CharPointer_ASCII& t) : text (StringHolder::createFromCharPointer (t)) { @@ -347,8 +367,9 @@ String::String (const wchar_t* const t, size_t maxChars) const String String::charToString (const juce_wchar character) { String result (Preallocation (1)); - result.text[0] = character; - result.text[1] = 0; + CharPointerType t (result.text); + t.write (character); + t.writeNull(); return result; } @@ -540,22 +561,22 @@ const juce_wchar String::operator[] (int index) const throw() int String::hashCode() const throw() { - const juce_wchar* t = text; + CharPointerType t (text); int result = 0; - while (*t != (juce_wchar) 0) - result = 31 * result + *t++; + while (! t.isEmpty()) + result = 31 * result + t.getAndAdvance(); return result; } int64 String::hashCode64() const throw() { - const juce_wchar* t = text; + CharPointerType t (text); int64 result = 0; - while (*t != (juce_wchar) 0) - result = 101 * result + *t++; + while (! t.isEmpty()) + result = 101 * result + t.getAndAdvance(); return result; } @@ -703,7 +724,6 @@ void String::append (const String& textToAppend, size_t maxCharsToTake) String& String::operator+= (const juce_wchar* const t) { appendCharPointer (CharPointer_UTF32 (t)); - return *this; } @@ -884,16 +904,7 @@ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const NewLine&) //============================================================================== int String::indexOfChar (const juce_wchar character) const throw() { - const juce_wchar* t = text; - - for (;;) - { - if (*t == character) - return (int) (t - text); - - if (*t++ == 0) - return -1; - } + return text.indexOf (character); } int String::lastIndexOfChar (const juce_wchar character) const throw() @@ -913,21 +924,8 @@ int String::indexOf (const String& t) const throw() int String::indexOfChar (const int startIndex, const juce_wchar character) const throw() { - if (startIndex > 0 && startIndex >= length()) - return -1; - - const juce_wchar* t = text + jmax (0, startIndex); - - for (;;) - { - if (*t == character) - return (int) (t - text); - - if (*t == 0) - return -1; - - ++t; - } + const int i = (text + startIndex).indexOf (character); + return i < 0 ? -1 : (i + startIndex); } int String::indexOfAnyOf (const String& charactersToLookFor, @@ -1058,18 +1056,7 @@ bool String::contains (const String& other) const throw() bool String::containsChar (const juce_wchar character) const throw() { - const juce_wchar* t = text; - - for (;;) - { - if (*t == 0) - return false; - - if (*t == character) - return true; - - ++t; - } + return text.indexOf (character) >= 0; } bool String::containsIgnoreCase (const String& t) const throw() @@ -1210,15 +1197,11 @@ const String String::repeatedString (const String& stringToRepeat, int numberOfT if (numberOfTimesToRepeat <= 0) return String::empty; - const int len = stringToRepeat.length(); - String result (Preallocation (len * numberOfTimesToRepeat + 1)); + String result (Preallocation (stringToRepeat.length() * numberOfTimesToRepeat + 1)); CharPointerType n (result.text); while (--numberOfTimesToRepeat >= 0) - { - StringHolder::copyChars (n, stringToRepeat.text, len); - n += len; - } + n.writeAll (stringToRepeat.text); return result; } @@ -1602,57 +1585,63 @@ const String String::quoted (const juce_wchar quoteCharacter) const } //============================================================================== -const String String::trim() const +static String::CharPointerType findTrimmedEnd (const String::CharPointerType& start, String::CharPointerType end) { - if (isEmpty()) - return empty; - - int start = 0; - - while ((text + start).isWhitespace()) - ++start; + while (end > start) + { + if (! (--end).isWhitespace()) + { + ++end; + break; + } + } - const int len = length(); - int end = len - 1; + return end; +} - while ((end >= start) && (text + end).isWhitespace()) - --end; +const String String::trim() const +{ + if (isNotEmpty()) + { + CharPointerType start (text.findEndOfWhitespace()); - ++end; + const CharPointerType end (start.findTerminatingNull()); + CharPointerType trimmedEnd (findTrimmedEnd (start, end)); - if (end <= start) - return empty; - else if (start > 0 || end < len) - return String (text + start, end - start); + if (trimmedEnd <= start) + return empty; + else if (text < start || trimmedEnd < end) + return String (start, trimmedEnd); + } return *this; } const String String::trimStart() const { - if (isEmpty()) - return empty; - - CharPointerType t (text.findEndOfWhitespace()); + if (isNotEmpty()) + { + const CharPointerType t (text.findEndOfWhitespace()); - if (t == text) - return *this; + if (t != text) + return String (t); + } - return String (t); + return *this; } const String String::trimEnd() const { - if (isEmpty()) - return empty; - - CharPointerType endT (text); - endT = endT.findTerminatingNull() - 1; + if (isNotEmpty()) + { + const CharPointerType end (text.findTerminatingNull()); + CharPointerType trimmedEnd (findTrimmedEnd (text, end)); - while ((endT.getAddress() >= text) && endT.isWhitespace()) - --endT; + if (trimmedEnd < end) + return String (text, trimmedEnd); + } - return String (text, 1 + (int) (endT.getAddress() - text)); + return *this; } const String String::trimCharactersAtStart (const String& charactersToTrim) const @@ -1667,20 +1656,25 @@ const String String::trimCharactersAtStart (const String& charactersToTrim) cons const String String::trimCharactersAtEnd (const String& charactersToTrim) const { - if (isEmpty()) - return empty; + if (isNotEmpty()) + { + const CharPointerType end (text.findTerminatingNull()); + CharPointerType trimmedEnd (end); - const int len = length(); - const juce_wchar* endT = text + (len - 1); - int numToRemove = 0; + while (trimmedEnd > text) + { + if (! charactersToTrim.containsChar (*--trimmedEnd)) + { + ++trimmedEnd; + break; + } + } - while (numToRemove < len && charactersToTrim.containsChar (*endT)) - { - ++numToRemove; - --endT; + if (trimmedEnd < end) + return String (text, trimmedEnd); } - return numToRemove > 0 ? String (text, len - numToRemove) : *this; + return *this; } //============================================================================== @@ -1734,33 +1728,32 @@ const String String::removeCharacters (const String& charactersToRemove) const const String String::initialSectionContainingOnly (const String& permittedCharacters) const { - int i = 0; + CharPointerType t (text); - for (;;) + while (! t.isEmpty()) { - if (! permittedCharacters.containsChar (text[i])) - break; + if (! permittedCharacters.containsChar (*t)) + return String (text, t); - ++i; + ++t; } - return substring (0, i); + return *this; } const String String::initialSectionNotContaining (const String& charactersToStopAt) const { - const juce_wchar* const t = text; - int i = 0; + CharPointerType t (text); - while (t[i] != 0) + while (! t.isEmpty()) { - if (charactersToStopAt.containsChar (t[i])) - return String (text, i); + if (charactersToStopAt.containsChar (*t)) + return String (text, t); - ++i; + ++t; } - return empty; + return *this; } bool String::containsOnly (const String& chars) const throw() @@ -1776,10 +1769,10 @@ bool String::containsOnly (const String& chars) const throw() bool String::containsAnyOf (const String& chars) const throw() { - const juce_wchar* t = text; + CharPointerType t (text); - while (*t != 0) - if (chars.containsChar (*t++)) + while (! t.isEmpty()) + if (chars.containsChar (t.getAndAdvance())) return true; return false; @@ -1892,40 +1885,50 @@ double String::getDoubleValue() const throw() static const char* const hexDigits = "0123456789abcdef"; -const String String::toHexString (const int number) +template +struct HexConverter { - juce_wchar buffer[32]; - juce_wchar* const end = buffer + 32; - juce_wchar* t = end; - *--t = 0; - unsigned int v = (unsigned int) number; - - do + static const String hexToString (Type v) { - *--t = (juce_wchar) hexDigits [v & 15]; - v >>= 4; + juce_wchar buffer[32]; + juce_wchar* const end = buffer + 32; + juce_wchar* t = end; + *--t = 0; - } while (v != 0); + do + { + *--t = (juce_wchar) hexDigits [(int) (v & 15)]; + v >>= 4; - return String (t, (int) (((char*) end) - (char*) t) - 1); -} + } while (v != 0); -const String String::toHexString (const int64 number) -{ - juce_wchar buffer[32]; - juce_wchar* const end = buffer + 32; - juce_wchar* t = end; - *--t = 0; - uint64 v = (uint64) number; + return String (t, (int) (end - t) - 1); + } - do + static Type stringToHex (String::CharPointerType t) throw() { - *--t = (juce_wchar) hexDigits [(int) (v & 15)]; - v >>= 4; + Type result = 0; + + while (! t.isEmpty()) + { + const int hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance()); + + if (hexValue >= 0) + result = (result << 4) | hexValue; + } + + return result; + } +}; - } while (v != 0); +const String String::toHexString (const int number) +{ + return HexConverter ::hexToString ((unsigned int) number); +} - return String (t, (int) (((char*) end) - (char*) t)); +const String String::toHexString (const int64 number) +{ + return HexConverter ::hexToString ((uint64) number); } const String String::toHexString (const short number) @@ -1962,34 +1965,12 @@ const String String::toHexString (const unsigned char* data, const int size, con int String::getHexValue32() const throw() { - int result = 0; - CharPointerType t (text); - - while (! t.isEmpty()) - { - const int hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance()); - - if (hexValue >= 0) - result = (result << 4) | hexValue; - } - - return result; + return HexConverter ::stringToHex (text); } int64 String::getHexValue64() const throw() { - int64 result = 0; - CharPointerType t (text); - - while (! t.isEmpty()) - { - const int hexValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance()); - - if (hexValue >= 0) - result = (result << 4) | hexValue; - } - - return result; + return HexConverter ::stringToHex (text); } //============================================================================== @@ -2005,8 +1986,10 @@ const String String::createStringFromData (const void* const data_, const int si { return charToString ((char) data[0]); } - else if ((data[0] == (uint8) CharPointer_UTF16::byteOrderMarkBE1 && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkBE2) - || (data[0] == (uint8) CharPointer_UTF16::byteOrderMarkLE1 && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkLE1)) + else if ((data[0] == (uint8) CharPointer_UTF16::byteOrderMarkBE1 + && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkBE2) + || (data[0] == (uint8) CharPointer_UTF16::byteOrderMarkLE1 + && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkLE1)) { const bool bigEndian = (data[0] == (uint8) CharPointer_UTF16::byteOrderMarkBE1); const int numChars = size / 2 - 1; @@ -2454,7 +2437,9 @@ public: expect (s5.removeCharacters ("1wordxya") == " 2 3"); expectEquals (s5.removeCharacters (String::empty), s5); expect (s5.initialSectionContainingOnly ("word") == L"word"); + expect (String ("word").initialSectionContainingOnly ("word") == L"word"); expectEquals (s5.initialSectionNotContaining (String ("xyz ")), String ("word")); + expectEquals (s5.initialSectionNotContaining (String (";[:'/")), s5); expect (! s5.isQuotedString()); expect (s5.quoted().isQuotedString()); expect (! s5.quoted().unquoted().isQuotedString()); diff --git a/src/text/juce_String.h b/src/text/juce_String.h index ccb7c6489a..05c31bc2f4 100644 --- a/src/text/juce_String.h +++ b/src/text/juce_String.h @@ -123,6 +123,9 @@ public: /** Creates a string from a UTF-32 character string */ String (const CharPointer_UTF32& text, size_t maxChars); + /** Creates a string from a UTF-32 character string */ + String (const CharPointer_UTF32& start, const CharPointer_UTF32& end); + /** Creates a string from an ASCII character string */ String (const CharPointer_ASCII& text); @@ -772,7 +775,8 @@ public: /** Returns a section from the start of the string that only contains a certain set of characters. This returns the leftmost section of the string, up to (and not including) the - first character that occurs in the string passed in. + first character that occurs in the string passed in. (If none of the specified + characters are found in the string, the return value will just be the original string). */ const String initialSectionNotContaining (const String& charactersToStopAt) const;