diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
index 3c9be7d63b..c4a5b64040 100644
--- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
@@ -1035,6 +1035,7 @@
4007410FACA2F865FD8EF769 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF8.h; path = ../../src/text/juce_CharPointer_UTF8.h; sourceTree = SOURCE_ROOT; };
663746215E9BA6C761172B85 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF16.h; path = ../../src/text/juce_CharPointer_UTF16.h; sourceTree = SOURCE_ROOT; };
C3FD9D93626F80A45F9B6DDE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF32.h; path = ../../src/text/juce_CharPointer_UTF32.h; sourceTree = SOURCE_ROOT; };
+ 72F5ED2E8B945988C37EA9CF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_ASCII.h; path = ../../src/text/juce_CharPointer_ASCII.h; sourceTree = SOURCE_ROOT; };
8273A206FB309671284959DD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Identifier.cpp; path = ../../src/text/juce_Identifier.cpp; sourceTree = SOURCE_ROOT; };
BF888BC540B64D5C61E46A34 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Identifier.h; path = ../../src/text/juce_Identifier.h; sourceTree = SOURCE_ROOT; };
4A97C8D2FF6454DDD3AF4BE5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_LocalisedStrings.cpp; path = ../../src/text/juce_LocalisedStrings.cpp; sourceTree = SOURCE_ROOT; };
@@ -1861,6 +1862,7 @@
4007410FACA2F865FD8EF769,
663746215E9BA6C761172B85,
C3FD9D93626F80A45F9B6DDE,
+ 72F5ED2E8B945988C37EA9CF,
8273A206FB309671284959DD,
BF888BC540B64D5C61E46A34,
4A97C8D2FF6454DDD3AF4BE5,
diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj
index 750f9e7fa9..7d44fa08f8 100644
--- a/Builds/VisualStudio2005/Juce.vcproj
+++ b/Builds/VisualStudio2005/Juce.vcproj
@@ -959,6 +959,7 @@
+
diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj
index 2bdf1e7208..477a1d35e8 100644
--- a/Builds/VisualStudio2008/Juce.vcproj
+++ b/Builds/VisualStudio2008/Juce.vcproj
@@ -959,6 +959,7 @@
+
diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj
index 392199c9bf..7322381ce9 100644
--- a/Builds/VisualStudio2008_DLL/Juce.vcproj
+++ b/Builds/VisualStudio2008_DLL/Juce.vcproj
@@ -961,6 +961,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj
index a25dcffc23..b3c4a813e7 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj
+++ b/Builds/VisualStudio2010/Juce.vcxproj
@@ -777,6 +777,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters
index 66b57290c0..7409e030d8 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj.filters
+++ b/Builds/VisualStudio2010/Juce.vcxproj.filters
@@ -2265,6 +2265,9 @@
Juce\Source\text
+
+ Juce\Source\text
+
Juce\Source\text
diff --git a/Builds/iOS/Juce.xcodeproj/project.pbxproj b/Builds/iOS/Juce.xcodeproj/project.pbxproj
index 473e91ec8b..3d1aefc0c0 100644
--- a/Builds/iOS/Juce.xcodeproj/project.pbxproj
+++ b/Builds/iOS/Juce.xcodeproj/project.pbxproj
@@ -1035,6 +1035,7 @@
4007410FACA2F865FD8EF769 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF8.h; path = ../../src/text/juce_CharPointer_UTF8.h; sourceTree = SOURCE_ROOT; };
663746215E9BA6C761172B85 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF16.h; path = ../../src/text/juce_CharPointer_UTF16.h; sourceTree = SOURCE_ROOT; };
C3FD9D93626F80A45F9B6DDE = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_UTF32.h; path = ../../src/text/juce_CharPointer_UTF32.h; sourceTree = SOURCE_ROOT; };
+ 72F5ED2E8B945988C37EA9CF = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_CharPointer_ASCII.h; path = ../../src/text/juce_CharPointer_ASCII.h; sourceTree = SOURCE_ROOT; };
8273A206FB309671284959DD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Identifier.cpp; path = ../../src/text/juce_Identifier.cpp; sourceTree = SOURCE_ROOT; };
BF888BC540B64D5C61E46A34 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Identifier.h; path = ../../src/text/juce_Identifier.h; sourceTree = SOURCE_ROOT; };
4A97C8D2FF6454DDD3AF4BE5 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_LocalisedStrings.cpp; path = ../../src/text/juce_LocalisedStrings.cpp; sourceTree = SOURCE_ROOT; };
@@ -1861,6 +1862,7 @@
4007410FACA2F865FD8EF769,
663746215E9BA6C761172B85,
C3FD9D93626F80A45F9B6DDE,
+ 72F5ED2E8B945988C37EA9CF,
8273A206FB309671284959DD,
BF888BC540B64D5C61E46A34,
4A97C8D2FF6454DDD3AF4BE5,
diff --git a/Juce.jucer b/Juce.jucer
index a57e48a41f..ff3554e823 100644
--- a/Juce.jucer
+++ b/Juce.jucer
@@ -1477,6 +1477,8 @@
file="src/text/juce_CharPointer_UTF16.h"/>
+
::max()));
+}
+
+String::String (const char* const t, const size_t maxChars)
+ : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t), maxChars))
+{
+ /* If you get an assertion here, then you're trying to create a string from 8-bit data
+ that contains values greater than 127. These can NOT be correctly converted to unicode
+ because there's no way for the String class to know what encoding was used to
+ create them. The source data could be UTF-8, ASCII or one of many local code-pages.
+
+ To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
+ string to the String class - so for example if your source data is actually UTF-8,
+ you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
+ correctly convert the multi-byte characters to unicode. It's *highly* recommended that
+ you use UTF-8 with escape characters in your source code to represent extended characters,
+ because there's no other way to represent these strings in a way that isn't dependent on
+ the compiler, source code editor and platform.
+ */
+ jassert (CharPointer_ASCII::isValidString (t, (int) maxChars));
}
String::String (const juce_wchar* const t)
@@ -11589,6 +11622,11 @@ String::String (const juce_wchar* const t)
{
}
+String::String (const juce_wchar* const t, const size_t maxChars)
+ : text (StringHolder::createFromCharPointer (CharPointer_UTF32 (t), maxChars))
+{
+}
+
String::String (const CharPointer_UTF8& t)
: text (StringHolder::createFromCharPointer (t))
{
@@ -11609,6 +11647,11 @@ String::String (const CharPointer_UTF32& t, const size_t maxChars)
{
}
+String::String (const CharPointer_ASCII& t)
+ : text (StringHolder::createFromCharPointer (t))
+{
+}
+
#if JUCE_WINDOWS
String::String (const wchar_t* const t)
: text (StringHolder::createFromCharPointer (CharPointer_UTF16 (t)))
@@ -11621,16 +11664,6 @@ String::String (const wchar_t* const t, size_t maxChars)
}
#endif
-String::String (const char* const t, const size_t maxChars)
- : text (StringHolder::createFromCharPointer (CharPointer_UTF8 (t), maxChars))
-{
-}
-
-String::String (const juce_wchar* const t, const size_t maxChars)
- : text (StringHolder::createFromCharPointer (CharPointer_UTF32 (t), maxChars))
-{
-}
-
const String String::charToString (const juce_wchar character)
{
String result (Preallocation (1));
@@ -12004,7 +12037,7 @@ String& String::operator+= (const juce_wchar ch)
}
#if JUCE_WINDOWS
-String& String::operator+= (wchar_t ch)
+String& String::operator+= (const wchar_t ch)
{
return operator+= ((juce_wchar) ch);
}
@@ -14551,7 +14584,7 @@ XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentEle
}
}
- input = static_cast (textToParse);
+ input = textToParse.getCharPointer();
lastError = String::empty;
errorOccurred = false;
outOfData = false;
@@ -14662,7 +14695,7 @@ void XmlDocument::skipHeader()
return;
input += docTypeIndex + 9;
- const CharPointer_UTF32 docType (input);
+ const String::CharPointerType docType (input);
int n = 1;
@@ -14751,7 +14784,7 @@ void XmlDocument::readQuotedString (String& result)
else
{
--input;
- const CharPointer_UTF32 start (input);
+ const String::CharPointerType start (input);
for (;;)
{
@@ -14759,14 +14792,14 @@ void XmlDocument::readQuotedString (String& result)
if (character == quote)
{
- result.append (start.getAddress(), (int) (input.getAddress() - start.getAddress()));
+ result.appendCharPointer (start, (int) (input.getAddress() - start.getAddress()));
++input;
return;
}
else if (character == '&')
{
- result.append (start.getAddress(), (int) (input.getAddress() - start.getAddress()));
+ result.appendCharPointer (start, (int) (input.getAddress() - start.getAddress()));
break;
}
else if (character == 0)
@@ -14846,7 +14879,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
if (attNameLen > 0)
{
- const CharPointer_UTF32 attNameStart (input);
+ const String::CharPointerType attNameStart (input);
input += attNameLen;
skipNextWhiteSpace();
@@ -14889,7 +14922,7 @@ void XmlDocument::readChildElements (XmlElement* parent)
for (;;)
{
- const CharPointer_UTF32 preWhitespaceInput (input);
+ const String::CharPointerType preWhitespaceInput (input);
skipNextWhiteSpace();
if (outOfData)
@@ -14920,7 +14953,7 @@ void XmlDocument::readChildElements (XmlElement* parent)
&& input[8] == '[')
{
input += 9;
- const CharPointer_UTF32 inputStart (input);
+ const String::CharPointerType inputStart (input);
int len = 0;
@@ -14983,10 +15016,10 @@ void XmlDocument::readChildElements (XmlElement* parent)
if (entity.startsWithChar ('<') && entity [1] != 0)
{
- const CharPointer_UTF32 oldInput (input);
+ const String::CharPointerType oldInput (input);
const bool oldOutOfData = outOfData;
- input = static_cast (entity);
+ input = entity.getCharPointer();
outOfData = false;
for (;;)
@@ -15009,7 +15042,7 @@ void XmlDocument::readChildElements (XmlElement* parent)
}
else
{
- const CharPointer_UTF32 start (input);
+ const String::CharPointerType start (input);
int len = 0;
for (;;)
@@ -15128,7 +15161,7 @@ void XmlDocument::readEntity (String& result)
}
else
{
- const CharPointer_UTF32 entityNameStart (input);
+ const String::CharPointerType entityNameStart (input);
const int closingSemiColon = input.indexOf ((juce_wchar) ';');
if (closingSemiColon < 0)
@@ -17525,24 +17558,68 @@ void ValueTree::SharedObject::sendPropertyChangeMessage (const Identifier& prope
}
}
-void ValueTree::SharedObject::sendChildChangeMessage (ValueTree& tree)
+void ValueTree::SharedObject::sendChildAddedMessage (ValueTree& tree, ValueTree& child)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != 0)
- v->listeners.call (&ValueTree::Listener::valueTreeChildrenChanged, tree);
+ v->listeners.call (&ValueTree::Listener::valueTreeChildAdded, tree, child);
}
}
-void ValueTree::SharedObject::sendChildChangeMessage()
+void ValueTree::SharedObject::sendChildAddedMessage (ValueTree child)
{
ValueTree tree (this);
ValueTree::SharedObject* t = this;
while (t != 0)
{
- t->sendChildChangeMessage (tree);
+ t->sendChildAddedMessage (tree, child);
+ t = t->parent;
+ }
+}
+
+void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree& tree, ValueTree& child)
+{
+ for (int i = valueTreesWithListeners.size(); --i >= 0;)
+ {
+ ValueTree* const v = valueTreesWithListeners[i];
+ if (v != 0)
+ v->listeners.call (&ValueTree::Listener::valueTreeChildRemoved, tree, child);
+ }
+}
+
+void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree child)
+{
+ ValueTree tree (this);
+ ValueTree::SharedObject* t = this;
+
+ while (t != 0)
+ {
+ t->sendChildRemovedMessage (tree, child);
+ t = t->parent;
+ }
+}
+
+void ValueTree::SharedObject::sendChildOrderChangedMessage (ValueTree& tree)
+{
+ for (int i = valueTreesWithListeners.size(); --i >= 0;)
+ {
+ ValueTree* const v = valueTreesWithListeners[i];
+ if (v != 0)
+ v->listeners.call (&ValueTree::Listener::valueTreeChildOrderChanged, tree);
+ }
+}
+
+void ValueTree::SharedObject::sendChildOrderChangedMessage()
+{
+ ValueTree tree (this);
+ ValueTree::SharedObject* t = this;
+
+ while (t != 0)
+ {
+ t->sendChildOrderChangedMessage (tree);
t = t->parent;
}
}
@@ -17708,7 +17785,7 @@ void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoMana
{
children.insert (index, child);
child->parent = this;
- sendChildChangeMessage();
+ sendChildAddedMessage (ValueTree (child));
child->sendParentChangeMessage();
}
else
@@ -17738,7 +17815,7 @@ void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* co
{
children.remove (childIndex);
child->parent = 0;
- sendChildChangeMessage();
+ sendChildRemovedMessage (ValueTree (child));
child->sendParentChangeMessage();
}
else
@@ -17765,7 +17842,7 @@ void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoMan
if (undoManager == 0)
{
children.move (currentIndex, newIndex);
- sendChildChangeMessage();
+ sendChildOrderChangedMessage();
}
else
{
@@ -17784,16 +17861,19 @@ void ValueTree::SharedObject::reorderChildren (const ReferenceCountedArray = 0);
+ moveChild (oldIndex, i, undoManager);
}
}
}
@@ -17990,8 +18070,10 @@ public:
sendChangeMessage (false);
}
- void valueTreeChildrenChanged (ValueTree&) {}
- void valueTreeParentChanged (ValueTree&) {}
+ void valueTreeChildAdded (ValueTree&, ValueTree&) {}
+ void valueTreeChildRemoved (ValueTree&, ValueTree&) {}
+ void valueTreeChildOrderChanged (ValueTree&) {}
+ void valueTreeParentChanged (ValueTree&) {}
private:
ValueTree tree;
@@ -23055,8 +23137,7 @@ public:
: AudioFormatWriter (out, TRANS (wavFormatName), sampleRate_, numChannels_, bits),
lengthInSamples (0),
bytesWritten (0),
- writeFailed (false),
- isRF64 (false)
+ writeFailed (false)
{
using namespace WavFileHelpers;
@@ -23123,7 +23204,7 @@ private:
MemoryBlock tempBlock, bwavChunk, smplChunk;
uint64 lengthInSamples, bytesWritten;
int64 headerPosition;
- bool writeFailed, isRF64;
+ bool writeFailed;
static int getChannelMask (const int numChannels) throw()
{
@@ -23152,14 +23233,15 @@ private:
const int bytesPerFrame = numChannels * bitsPerSample / 8;
int64 audioDataSize = bytesPerFrame * lengthInSamples;
- int64 riffChunkSize = 4 /* 'WAVE' */ + 8 + 40 /* WAVEFORMATEX */
+ const bool isRF64 = (bytesWritten >= literal64bit (0x100000000));
+
+ int64 riffChunkSize = 4 /* 'RIFF' */ + 8 + 40 /* WAVEFORMATEX */
+ 8 + audioDataSize + (audioDataSize & 1)
+ (bwavChunk.getSize() > 0 ? (8 + bwavChunk.getSize()) : 0)
+ (smplChunk.getSize() > 0 ? (8 + smplChunk.getSize()) : 0)
- + (8 + 28); // (JUNK chunk)
+ + (8 + 28); // (ds64 chunk)
riffChunkSize += (riffChunkSize & 0x1);
- isRF64 = (riffChunkSize > 0xffffffff);
output->writeInt (chunkName (isRF64 ? "RF64" : "RIFF"));
output->writeInt (isRF64 ? -1 : (int) riffChunkSize);
@@ -23167,10 +23249,9 @@ private:
if (! isRF64)
{
- // write Junk chunk
output->writeInt (chunkName ("JUNK"));
- output->writeInt (28);
- output->writeRepeatedByte (0, 28);
+ output->writeInt (28 + 24);
+ output->writeRepeatedByte (0, 28 /* ds64 */ + 24 /* extra waveformatex */);
}
else
{
@@ -23183,29 +23264,44 @@ private:
}
output->writeInt (chunkName ("fmt "));
- output->writeInt (40); // WAVEFORMATEX chunk size
- output->writeShort ((short) (uint16) 0xfffe); // WAVE_FORMAT_EXTENSIBLE
+
+ if (isRF64)
+ {
+ output->writeInt (40); // chunk size
+ output->writeShort ((short) (uint16) 0xfffe); // WAVE_FORMAT_EXTENSIBLE
+ }
+ else
+ {
+ output->writeInt (16); // chunk size
+ output->writeShort (bitsPerSample < 32 ? (short) 1 /*WAVE_FORMAT_PCM*/
+ : (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/);
+ }
+
output->writeShort ((short) numChannels);
output->writeInt ((int) sampleRate);
output->writeInt ((int) (bytesPerFrame * sampleRate)); // nAvgBytesPerSec
output->writeShort ((short) bytesPerFrame); // nBlockAlign
output->writeShort ((short) bitsPerSample); // wBitsPerSample
- output->writeShort (22); // cbSize (size of the extension)
- output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
- output->writeInt (getChannelMask (numChannels));
- const ExtensibleWavSubFormat pcmFormat
- = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+ if (isRF64)
+ {
+ output->writeShort (22); // cbSize (size of the extension)
+ output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
+ output->writeInt (getChannelMask (numChannels));
- const ExtensibleWavSubFormat IEEEFloatFormat
- = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+ const ExtensibleWavSubFormat pcmFormat
+ = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
- const ExtensibleWavSubFormat& subFormat = bitsPerSample < 32 ? pcmFormat : IEEEFloatFormat;
+ const ExtensibleWavSubFormat IEEEFloatFormat
+ = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
- output->writeInt ((int) subFormat.data1);
- output->writeShort ((short) subFormat.data2);
- output->writeShort ((short) subFormat.data3);
- output->write (subFormat.data4, sizeof (subFormat.data4));
+ const ExtensibleWavSubFormat& subFormat = bitsPerSample < 32 ? pcmFormat : IEEEFloatFormat;
+
+ output->writeInt ((int) subFormat.data1);
+ output->writeShort ((short) subFormat.data2);
+ output->writeShort ((short) subFormat.data3);
+ output->write (subFormat.data4, sizeof (subFormat.data4));
+ }
if (bwavChunk.getSize() > 0)
{
@@ -43750,6 +43846,7 @@ void DrawableButton::buttonStateChanged()
if (currentImage != 0)
{
+ currentImage->setInterceptsMouseClicks (false, false);
addAndMakeVisible (currentImage);
DrawableButton::resized();
}
@@ -54423,6 +54520,11 @@ void TextEditor::coalesceSimilarSections()
}
}
+void TextEditor::Listener::textEditorTextChanged (TextEditor&) {}
+void TextEditor::Listener::textEditorReturnKeyPressed (TextEditor&) {}
+void TextEditor::Listener::textEditorEscapeKeyPressed (TextEditor&) {}
+void TextEditor::Listener::textEditorFocusLost (TextEditor&) {}
+
END_JUCE_NAMESPACE
/*** End of inlined file: juce_TextEditor.cpp ***/
@@ -61303,7 +61405,17 @@ void ComponentBuilder::valueTreePropertyChanged (ValueTree& tree, const Identifi
ComponentBuilderHelpers::updateComponent (*this, tree);
}
-void ComponentBuilder::valueTreeChildrenChanged (ValueTree& tree)
+void ComponentBuilder::valueTreeChildAdded (ValueTree& tree, ValueTree&)
+{
+ ComponentBuilderHelpers::updateComponent (*this, tree);
+}
+
+void ComponentBuilder::valueTreeChildRemoved (ValueTree& tree, ValueTree&)
+{
+ ComponentBuilderHelpers::updateComponent (*this, tree);
+}
+
+void ComponentBuilder::valueTreeChildOrderChanged (ValueTree& tree)
{
ComponentBuilderHelpers::updateComponent (*this, tree);
}
@@ -68738,17 +68850,21 @@ class PopupMenu::ItemComponent : public Component
{
public:
- ItemComponent (const PopupMenu::Item& itemInfo_, int standardItemHeight)
+ ItemComponent (const PopupMenu::Item& itemInfo_, int standardItemHeight, Component* const parent)
: itemInfo (itemInfo_),
isHighlighted (false)
{
if (itemInfo.customComp != 0)
addAndMakeVisible (itemInfo.customComp);
+ parent->addAndMakeVisible (this);
+
int itemW = 80;
int itemH = 16;
getIdealSize (itemW, itemH, standardItemHeight);
setSize (itemW, jlimit (2, 600, itemH));
+
+ addMouseListener (parent, false);
}
~ItemComponent()
@@ -68877,12 +68993,7 @@ public:
setOpaque (getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque() || ! Desktop::canUseSemiTransparentWindows());
for (int i = 0; i < menu.items.size(); ++i)
- {
- PopupMenu::ItemComponent* const itemComp = new PopupMenu::ItemComponent (*menu.items.getUnchecked(i), standardItemHeight);
- items.add (itemComp);
- addAndMakeVisible (itemComp);
- itemComp->addMouseListener (this, false);
- }
+ items.add (new PopupMenu::ItemComponent (*menu.items.getUnchecked(i), standardItemHeight, this));
calculateWindowPos (target, alignToRectangle);
setTopLeftPosition (windowPos.getX(), windowPos.getY());
@@ -86175,6 +86286,12 @@ const Rectangle DrawableShape::getDrawableBounds() const
bool DrawableShape::hitTest (int x, int y)
{
+ bool allowsClicksOnThisComponent, allowsClicksOnChildComponents;
+ getInterceptsMouseClicks (allowsClicksOnThisComponent, allowsClicksOnChildComponents);
+
+ if (! allowsClicksOnThisComponent)
+ return false;
+
const float globalX = (float) (x - originRelativeToComponent.getX());
const float globalY = (float) (y - originRelativeToComponent.getY());
@@ -244209,7 +244326,7 @@ void SystemClipboard::copyTextToClipboard (const String& text)
{
if (EmptyClipboard() != 0)
{
- const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
+ const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer()) + 4;
if (bytesNeeded > 0)
{
@@ -263990,7 +264107,7 @@ namespace FileHelpers
FSRef ref;
LSItemInfoRecord info;
- return FSPathMakeRefWithOptions ((const UInt8*) path.toUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
+ return FSPathMakeRefWithOptions ((const UInt8*) path.toUTF8().getAddress(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
&& (info.flags & kLSItemInfoIsInvisible) != 0;
#endif
diff --git a/juce_amalgamated.h b/juce_amalgamated.h
index e311ae6102..8fefffd118 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 21
+#define JUCE_BUILDNUMBER 23
/** Current Juce version number.
@@ -2496,9 +2496,9 @@ public:
if (byte >= 0)
return byte;
- juce_wchar n = byte;
- juce_wchar mask = 0x7f;
- juce_wchar bit = 0x40;
+ uint32 n = (uint32) (uint8) byte;
+ uint32 mask = 0x7f;
+ uint32 bit = 0x40;
size_t numExtraValues = 0;
while ((n & bit) != 0 && bit > 0x10)
@@ -2521,7 +2521,7 @@ public:
n |= (nextByte & 0x3f);
}
- return n;
+ return (juce_wchar) n;
}
/** Moves this pointer along to the next character in the string. */
@@ -2881,6 +2881,51 @@ public:
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF8 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 0x10ffff;
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ {
+ const char byte = *dataToTest;
+
+ if (byte < 0)
+ {
+ uint32 n = (uint32) (uint8) byte;
+ uint32 mask = 0x7f;
+ uint32 bit = 0x40;
+ int numExtraValues = 0;
+
+ while ((n & bit) != 0)
+ {
+ if (bit <= 0x10)
+ return false;
+
+ mask >>= 1;
+ ++numExtraValues;
+ bit >>= 1;
+ }
+
+ n &= mask;
+
+ while (--numExtraValues >= 0)
+ {
+ const uint32 nextByte = (uint32) (uint8) *dataToTest++;
+
+ if ((nextByte & 0xc0) != 0x80)
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
/** These values are the byte-order-mark (BOM) values for a UTF-8 stream. */
enum
{
@@ -3268,6 +3313,43 @@ public:
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF16 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 0x10ffff
+ && (((unsigned int) character) < 0xd800 || ((unsigned int) character) > 0xdfff);
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ maxBytesToRead /= sizeof (CharType);
+
+ while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ {
+ const uint32 n = (uint32) (uint16) *dataToTest++;
+
+ if (n >= 0xd800)
+ {
+ if (n > 0x10ffff)
+ return false;
+
+ if (n <= 0xdfff)
+ {
+ if (n > 0xdc00)
+ return false;
+
+ const uint32 nextChar = (uint32) (uint16) *dataToTest++;
+
+ if (nextChar < 0xdc00 || nextChar > 0xdfff)
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
/** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */
enum
{
@@ -3377,7 +3459,7 @@ public:
CharPointer_UTF32 operator++ (int) throw()
{
CharPointer_UTF32 temp (*this);
- ++*this;
+ ++data;
return temp;
}
@@ -3612,6 +3694,25 @@ public:
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF32 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 0x10ffff;
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ maxBytesToRead /= sizeof (CharType);
+
+ while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ if (! canRepresent (*dataToTest++))
+ return false;
+
+ return true;
+ }
+
+ /** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF32 atomicSwap (const CharPointer_UTF32& newValue)
{
return CharPointer_UTF32 (reinterpret_cast &> (data).exchange (newValue.data));
@@ -3624,6 +3725,364 @@ private:
#endif // __JUCE_CHARPOINTER_UTF32_JUCEHEADER__
/*** End of inlined file: juce_CharPointer_UTF32.h ***/
+
+/*** Start of inlined file: juce_CharPointer_ASCII.h ***/
+#ifndef __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
+#define __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
+
+/**
+ Wraps a pointer to a null-terminated ASCII character string, and provides
+ various methods to operate on the data.
+
+ A valid ASCII string is assumed to not contain any characters above 127.
+
+ @see CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
+*/
+class CharPointer_ASCII
+{
+public:
+ typedef char CharType;
+
+ inline explicit CharPointer_ASCII (const CharType* const rawPointer) throw()
+ : data (const_cast (rawPointer))
+ {
+ }
+
+ inline CharPointer_ASCII (const CharPointer_ASCII& other) throw()
+ : data (other.data)
+ {
+ }
+
+ inline CharPointer_ASCII& operator= (const CharPointer_ASCII& other) throw()
+ {
+ data = other.data;
+ return *this;
+ }
+
+ inline CharPointer_ASCII& operator= (const CharType* text) throw()
+ {
+ data = const_cast (text);
+ return *this;
+ }
+
+ /** 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;
+ }
+
+ /** Returns the address that this pointer is pointing to. */
+ inline CharType* getAddress() const throw() { return data; }
+
+ /** Returns the address that this pointer is pointing to. */
+ inline operator const CharType*() const throw() { return data; }
+
+ /** Returns true if this pointer is pointing to a null character. */
+ inline bool isEmpty() const throw() { return *data == 0; }
+
+ /** Returns the unicode character that this pointer is pointing to. */
+ inline juce_wchar operator*() const throw() { return *data; }
+
+ /** Moves this pointer along to the next character in the string. */
+ inline CharPointer_ASCII& operator++() throw()
+ {
+ ++data;
+ return *this;
+ }
+
+ /** Moves this pointer to the previous character in the string. */
+ inline CharPointer_ASCII& operator--() throw()
+ {
+ --data;
+ return *this;
+ }
+
+ /** Returns the character that this pointer is currently pointing to, and then
+ advances the pointer to point to the next character. */
+ inline juce_wchar getAndAdvance() throw() { return *data++; }
+
+ /** Moves this pointer along to the next character in the string. */
+ CharPointer_ASCII operator++ (int) throw()
+ {
+ CharPointer_ASCII temp (*this);
+ ++data;
+ return temp;
+ }
+
+ /** Moves this pointer forwards by the specified number of characters. */
+ inline void operator+= (const int numToSkip) throw()
+ {
+ data += numToSkip;
+ }
+
+ inline void operator-= (const int numToSkip) throw()
+ {
+ data -= numToSkip;
+ }
+
+ /** Returns the character at a given character index from the start of the string. */
+ inline juce_wchar operator[] (const int characterIndex) const throw()
+ {
+ return (juce_wchar) (unsigned char) data [characterIndex];
+ }
+
+ /** Returns a pointer which is moved forwards from this one by the specified number of characters. */
+ CharPointer_ASCII operator+ (const int numToSkip) const throw()
+ {
+ return CharPointer_ASCII (data + numToSkip);
+ }
+
+ /** Returns a pointer which is moved backwards from this one by the specified number of characters. */
+ CharPointer_ASCII operator- (const int numToSkip) const throw()
+ {
+ return CharPointer_ASCII (data - numToSkip);
+ }
+
+ /** Writes a unicode character to this string, and advances this pointer to point to the next position. */
+ inline void write (const juce_wchar charToWrite) throw()
+ {
+ *data++ = (char) charToWrite;
+ }
+
+ inline void replaceChar (const juce_wchar newChar) throw()
+ {
+ *data = (char) newChar;
+ }
+
+ /** Writes a null character to this string (leaving the pointer's position unchanged). */
+ inline void writeNull() const throw()
+ {
+ *data = 0;
+ }
+
+ /** Returns the number of characters in this string. */
+ size_t length() const throw()
+ {
+ return (size_t) strlen (data);
+ }
+
+ /** Returns the number of characters in this string, or the given value, whichever is lower. */
+ size_t lengthUpTo (const size_t maxCharsToCount) const throw()
+ {
+ return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
+ }
+
+ /** Returns the number of bytes that are used to represent this string.
+ This includes the terminating null character.
+ */
+ size_t sizeInBytes() const throw()
+ {
+ return length() + 1;
+ }
+
+ /** Returns the number of bytes that would be needed to represent the given
+ unicode character in this encoding format.
+ */
+ static inline size_t getBytesRequiredFor (const juce_wchar) throw()
+ {
+ return 1;
+ }
+
+ /** Returns the number of bytes that would be needed to represent the given
+ string in this encoding format.
+ The value returned does NOT include the terminating null character.
+ */
+ template
+ static size_t getBytesRequiredFor (const CharPointer& text) throw()
+ {
+ return text.length();
+ }
+
+ /** Returns a pointer to the null character that terminates this string. */
+ CharPointer_ASCII findTerminatingNull() const throw()
+ {
+ return CharPointer_ASCII (data + length());
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes. */
+ template
+ void writeAll (const CharPointer& src) throw()
+ {
+ CharacterFunctions::copyAll (*this, src);
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes. */
+ void writeAll (const CharPointer_ASCII& src) throw()
+ {
+ strcpy (data, src.data);
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes.
+ The maxDestBytes parameter specifies the maximum number of bytes that can be written
+ to the destination buffer before stopping.
+ */
+ template
+ int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw()
+ {
+ return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes.
+ The maxChars parameter specifies the maximum number of characters that can be
+ written to the destination buffer before stopping (including the terminating null).
+ */
+ template
+ void writeWithCharLimit (const CharPointer& src, const int maxChars) throw()
+ {
+ CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
+ }
+
+ /** Compares this string with another one. */
+ template
+ int compare (const CharPointer& other) const throw()
+ {
+ return CharacterFunctions::compare (*this, other);
+ }
+
+ /** Compares this string with another one. */
+ int compare (const CharPointer_ASCII& other) const throw()
+ {
+ return strcmp (data, other.data);
+ }
+
+ /** Compares this string with another one, up to a specified number of characters. */
+ template
+ int compareUpTo (const CharPointer& other, const int maxChars) const throw()
+ {
+ return CharacterFunctions::compareUpTo (*this, other, maxChars);
+ }
+
+ /** Compares this string with another one, up to a specified number of characters. */
+ int compareUpTo (const CharPointer_ASCII& other, const int maxChars) const throw()
+ {
+ return strncmp (data, other.data, (size_t) maxChars);
+ }
+
+ /** Compares this string with another one. */
+ template
+ int compareIgnoreCase (const CharPointer& other) const
+ {
+ return CharacterFunctions::compareIgnoreCase (*this, other);
+ }
+
+ int compareIgnoreCase (const CharPointer_ASCII& other) const
+ {
+ #if JUCE_WINDOWS
+ return stricmp (data, other.data);
+ #else
+ return strcasecmp (data, other.data);
+ #endif
+ }
+
+ /** Compares this string with another one, up to a specified number of characters. */
+ template
+ int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw()
+ {
+ return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
+ }
+
+ /** Returns the character index of a substring, or -1 if it isn't found. */
+ template
+ int indexOf (const CharPointer& stringToFind) const throw()
+ {
+ return CharacterFunctions::indexOf (*this, stringToFind);
+ }
+
+ /** Returns the character index of a unicode character, or -1 if it isn't found. */
+ int indexOf (const juce_wchar charToFind) const throw()
+ {
+ int i = 0;
+
+ while (data[i] != 0)
+ {
+ if (data[i] == (char) charToFind)
+ return i;
+
+ ++i;
+ }
+
+ return -1;
+ }
+
+ /** Returns the character index of a unicode character, or -1 if it isn't found. */
+ int indexOf (const juce_wchar charToFind, const bool ignoreCase) const throw()
+ {
+ return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
+ : CharacterFunctions::indexOfChar (*this, charToFind);
+ }
+
+ /** Returns true if the first character of this string is whitespace. */
+ bool isWhitespace() const { return CharacterFunctions::isWhitespace (*data) != 0; }
+ /** Returns true if the first character of this string is a digit. */
+ bool isDigit() const { return CharacterFunctions::isDigit (*data) != 0; }
+ /** Returns true if the first character of this string is a letter. */
+ bool isLetter() const { return CharacterFunctions::isLetter (*data) != 0; }
+ /** Returns true if the first character of this string is a letter or digit. */
+ bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
+ /** Returns true if the first character of this string is upper-case. */
+ bool isUpperCase() const { return CharacterFunctions::isUpperCase (*data) != 0; }
+ /** Returns true if the first character of this string is lower-case. */
+ bool isLowerCase() const { return CharacterFunctions::isLowerCase (*data) != 0; }
+
+ /** Returns an upper-case version of the first character of this string. */
+ juce_wchar toUpperCase() const throw() { return CharacterFunctions::toUpperCase (*data); }
+ /** Returns a lower-case version of the first character of this string. */
+ juce_wchar toLowerCase() const throw() { return CharacterFunctions::toLowerCase (*data); }
+
+ /** Parses this string as a 32-bit integer. */
+ int getIntValue32() const throw() { return atoi (data); }
+
+ /** Parses this string as a 64-bit integer. */
+ int64 getIntValue64() const throw()
+ {
+ #if JUCE_LINUX || JUCE_ANDROID
+ return atoll (data);
+ #elif JUCE_WINDOWS
+ return _atoi64 (data);
+ #else
+ return CharacterFunctions::getIntValue (*this);
+ #endif
+ }
+
+ /** Parses this string as a floating point double. */
+ double getDoubleValue() const throw() { return CharacterFunctions::getDoubleValue (*this); }
+
+ /** Returns the first non-whitespace character in the string. */
+ CharPointer_ASCII findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 128;
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ while (--maxBytesToRead >= 0)
+ {
+ if (*dataToTest <= 0)
+ return *dataToTest == 0;
+
+ ++dataToTest;
+ }
+
+ return true;
+ }
+
+private:
+ CharType* data;
+};
+
+#endif // __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
+/*** End of inlined file: juce_CharPointer_ASCII.h ***/
+
#if JUCE_MSVC
#pragma warning (pop)
#endif
@@ -3644,7 +4103,6 @@ class JUCE_API String
public:
/** Creates an empty string.
-
@see empty
*/
String() throw();
@@ -3652,15 +4110,36 @@ public:
/** Creates a copy of another string. */
String (const String& other) throw();
- /** Creates a string from a zero-terminated text string.
- The string is assumed to be stored in the default system encoding.
+ /** Creates a string from a zero-terminated ascii text string.
+
+ The string passed-in must not contain any characters with a value above 127, because
+ these can't be converted to unicode without knowing the original encoding that was
+ used to create the string. If you attempt to pass-in values above 127, you'll get an
+ assertion.
+
+ To create strings with extended characters from UTF-8, you should explicitly call
+ String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
+ use UTF-8 with escape characters in your source code to represent extended characters,
+ because there's no other way to represent unicode strings in a way that isn't dependent
+ on the compiler, source code editor and platform.
*/
String (const char* text);
- /** Creates a string from an string of characters.
+ /** Creates a string from a string of 8-bit ascii characters.
- This will use up the the first maxChars characters of the string (or
- less if the string is actually shorter)
+ The string passed-in must not contain any characters with a value above 127, because
+ these can't be converted to unicode without knowing the original encoding that was
+ used to create the string. If you attempt to pass-in values above 127, you'll get an
+ assertion.
+
+ To create strings with extended characters from UTF-8, you should explicitly call
+ String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
+ use UTF-8 with escape characters in your source code to represent extended characters,
+ because there's no other way to represent unicode strings in a way that isn't dependent
+ on the compiler, source code editor and platform.
+
+ This will use up the the first maxChars characters of the string (or less if the string
+ is actually shorter).
*/
String (const char* text, size_t maxChars);
@@ -3686,6 +4165,9 @@ public:
/** Creates a string from a UTF-32 character string */
String (const CharPointer_UTF32& text, size_t maxChars);
+ /** Creates a string from an ASCII character string */
+ String (const CharPointer_ASCII& text);
+
#if JUCE_WINDOWS
/** Creates a string from a UTF-16 character string */
String (const wchar_t* text);
@@ -15559,16 +16041,34 @@ public:
virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) = 0;
- /** This method is called when a child sub-tree is added or removed.
-
- The tree parameter indicates the tree whose child was added or removed.
+ /** This method is called when a child sub-tree is added.
Note that when you register a listener to a tree, it will receive this callback for
- child changes in that tree, and also in any of its children, (recursively, at any depth).
+ child changes in both that tree and any of its children, (recursively, at any depth).
If your tree has sub-trees but you only want to know about changes to the top level tree,
- simply check the tree parameter in this callback to make sure it's the tree you're interested in.
+ just check the parentTree parameter to make sure it's the one that you're interested in.
*/
- virtual void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged) = 0;
+ virtual void valueTreeChildAdded (ValueTree& parentTree,
+ ValueTree& childWhichHasBeenAdded) = 0;
+
+ /** This method is called when a child sub-tree is removed.
+
+ Note that when you register a listener to a tree, it will receive this callback for
+ child changes in both that tree and any of its children, (recursively, at any depth).
+ If your tree has sub-trees but you only want to know about changes to the top level tree,
+ just check the parentTree parameter to make sure it's the one that you're interested in.
+ */
+ virtual void valueTreeChildRemoved (ValueTree& parentTree,
+ ValueTree& childWhichHasBeenRemoved) = 0;
+
+ /** This method is called when a tree's children have been re-shuffled.
+
+ Note that when you register a listener to a tree, it will receive this callback for
+ child changes in both that tree and any of its children, (recursively, at any depth).
+ If your tree has sub-trees but you only want to know about changes to the top level tree,
+ just check the parameter to make sure it's the tree that you're interested in.
+ */
+ virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved) = 0;
/** This method is called when a tree has been added or removed from a parent node.
@@ -15660,8 +16160,12 @@ private:
void sendPropertyChangeMessage (const Identifier& property);
void sendPropertyChangeMessage (ValueTree& tree, const Identifier& property);
- void sendChildChangeMessage();
- void sendChildChangeMessage (ValueTree& tree);
+ void sendChildAddedMessage (ValueTree& parent, ValueTree& child);
+ void sendChildAddedMessage (ValueTree child);
+ void sendChildRemovedMessage (ValueTree& parent, ValueTree& child);
+ void sendChildRemovedMessage (ValueTree child);
+ void sendChildOrderChangedMessage (ValueTree& parent);
+ void sendChildOrderChangedMessage();
void sendParentChangeMessage();
const var& getProperty (const Identifier& name) const;
const var getProperty (const Identifier& name, const var& defaultReturnValue) const;
@@ -20054,6 +20558,9 @@ private:
#endif
#ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__
+#endif
+#ifndef __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
+
#endif
#ifndef __JUCE_CHARPOINTER_UTF16_JUCEHEADER__
@@ -20368,7 +20875,7 @@ public:
private:
String originalText;
- CharPointer_UTF32 input;
+ String::CharPointerType input;
bool outOfData, errorOccurred;
String lastError, dtdText;
@@ -40505,16 +41012,16 @@ public:
virtual ~Listener() {}
/** Called when the user changes the text in some way. */
- virtual void textEditorTextChanged (TextEditor& editor) = 0;
+ virtual void textEditorTextChanged (TextEditor& editor);
/** Called when the user presses the return key. */
- virtual void textEditorReturnKeyPressed (TextEditor& editor) = 0;
+ virtual void textEditorReturnKeyPressed (TextEditor& editor);
/** Called when the user presses the escape key. */
- virtual void textEditorEscapeKeyPressed (TextEditor& editor) = 0;
+ virtual void textEditorEscapeKeyPressed (TextEditor& editor);
/** Called when the text editor loses focus. */
- virtual void textEditorFocusLost (TextEditor& editor) = 0;
+ virtual void textEditorFocusLost (TextEditor& editor);
};
/** Registers a listener to be told when things happen to the text.
@@ -47918,7 +48425,11 @@ public:
/** @internal */
void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property);
/** @internal */
- void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged);
+ void valueTreeChildAdded (ValueTree& parentTree, ValueTree& childWhichHasBeenAdded);
+ /** @internal */
+ void valueTreeChildRemoved (ValueTree& parentTree, ValueTree& childWhichHasBeenRemoved);
+ /** @internal */
+ void valueTreeChildOrderChanged (ValueTree& parentTree);
/** @internal */
void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged);
diff --git a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp
index 12c077e151..64401dd6e7 100644
--- a/src/audio/audio_file_formats/juce_WavAudioFormat.cpp
+++ b/src/audio/audio_file_formats/juce_WavAudioFormat.cpp
@@ -498,8 +498,7 @@ public:
: AudioFormatWriter (out, TRANS (wavFormatName), sampleRate_, numChannels_, bits),
lengthInSamples (0),
bytesWritten (0),
- writeFailed (false),
- isRF64 (false)
+ writeFailed (false)
{
using namespace WavFileHelpers;
@@ -567,7 +566,7 @@ private:
MemoryBlock tempBlock, bwavChunk, smplChunk;
uint64 lengthInSamples, bytesWritten;
int64 headerPosition;
- bool writeFailed, isRF64;
+ bool writeFailed;
static int getChannelMask (const int numChannels) throw()
{
@@ -596,14 +595,15 @@ private:
const int bytesPerFrame = numChannels * bitsPerSample / 8;
int64 audioDataSize = bytesPerFrame * lengthInSamples;
- int64 riffChunkSize = 4 /* 'WAVE' */ + 8 + 40 /* WAVEFORMATEX */
+ const bool isRF64 = (bytesWritten >= literal64bit (0x100000000));
+
+ int64 riffChunkSize = 4 /* 'RIFF' */ + 8 + 40 /* WAVEFORMATEX */
+ 8 + audioDataSize + (audioDataSize & 1)
+ (bwavChunk.getSize() > 0 ? (8 + bwavChunk.getSize()) : 0)
+ (smplChunk.getSize() > 0 ? (8 + smplChunk.getSize()) : 0)
- + (8 + 28); // (JUNK chunk)
+ + (8 + 28); // (ds64 chunk)
riffChunkSize += (riffChunkSize & 0x1);
- isRF64 = (riffChunkSize > 0xffffffff);
output->writeInt (chunkName (isRF64 ? "RF64" : "RIFF"));
output->writeInt (isRF64 ? -1 : (int) riffChunkSize);
@@ -611,10 +611,9 @@ private:
if (! isRF64)
{
- // write Junk chunk
output->writeInt (chunkName ("JUNK"));
- output->writeInt (28);
- output->writeRepeatedByte (0, 28);
+ output->writeInt (28 + 24);
+ output->writeRepeatedByte (0, 28 /* ds64 */ + 24 /* extra waveformatex */);
}
else
{
@@ -627,29 +626,44 @@ private:
}
output->writeInt (chunkName ("fmt "));
- output->writeInt (40); // WAVEFORMATEX chunk size
- output->writeShort ((short) (uint16) 0xfffe); // WAVE_FORMAT_EXTENSIBLE
+
+ if (isRF64)
+ {
+ output->writeInt (40); // chunk size
+ output->writeShort ((short) (uint16) 0xfffe); // WAVE_FORMAT_EXTENSIBLE
+ }
+ else
+ {
+ output->writeInt (16); // chunk size
+ output->writeShort (bitsPerSample < 32 ? (short) 1 /*WAVE_FORMAT_PCM*/
+ : (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/);
+ }
+
output->writeShort ((short) numChannels);
output->writeInt ((int) sampleRate);
output->writeInt ((int) (bytesPerFrame * sampleRate)); // nAvgBytesPerSec
output->writeShort ((short) bytesPerFrame); // nBlockAlign
output->writeShort ((short) bitsPerSample); // wBitsPerSample
- output->writeShort (22); // cbSize (size of the extension)
- output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
- output->writeInt (getChannelMask (numChannels));
- const ExtensibleWavSubFormat pcmFormat
- = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+ if (isRF64)
+ {
+ output->writeShort (22); // cbSize (size of the extension)
+ output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
+ output->writeInt (getChannelMask (numChannels));
- const ExtensibleWavSubFormat IEEEFloatFormat
- = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
+ const ExtensibleWavSubFormat pcmFormat
+ = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
- const ExtensibleWavSubFormat& subFormat = bitsPerSample < 32 ? pcmFormat : IEEEFloatFormat;
+ const ExtensibleWavSubFormat IEEEFloatFormat
+ = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
- output->writeInt ((int) subFormat.data1);
- output->writeShort ((short) subFormat.data2);
- output->writeShort ((short) subFormat.data3);
- output->write (subFormat.data4, sizeof (subFormat.data4));
+ const ExtensibleWavSubFormat& subFormat = bitsPerSample < 32 ? pcmFormat : IEEEFloatFormat;
+
+ output->writeInt ((int) subFormat.data1);
+ output->writeShort ((short) subFormat.data2);
+ output->writeShort ((short) subFormat.data3);
+ output->write (subFormat.data4, sizeof (subFormat.data4));
+ }
if (bwavChunk.getSize() > 0)
{
diff --git a/src/containers/juce_ValueTree.cpp b/src/containers/juce_ValueTree.cpp
index 3213260231..c615f3047f 100644
--- a/src/containers/juce_ValueTree.cpp
+++ b/src/containers/juce_ValueTree.cpp
@@ -250,24 +250,68 @@ void ValueTree::SharedObject::sendPropertyChangeMessage (const Identifier& prope
}
}
-void ValueTree::SharedObject::sendChildChangeMessage (ValueTree& tree)
+void ValueTree::SharedObject::sendChildAddedMessage (ValueTree& tree, ValueTree& child)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != 0)
- v->listeners.call (&ValueTree::Listener::valueTreeChildrenChanged, tree);
+ v->listeners.call (&ValueTree::Listener::valueTreeChildAdded, tree, child);
}
}
-void ValueTree::SharedObject::sendChildChangeMessage()
+void ValueTree::SharedObject::sendChildAddedMessage (ValueTree child)
{
ValueTree tree (this);
ValueTree::SharedObject* t = this;
while (t != 0)
{
- t->sendChildChangeMessage (tree);
+ t->sendChildAddedMessage (tree, child);
+ t = t->parent;
+ }
+}
+
+void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree& tree, ValueTree& child)
+{
+ for (int i = valueTreesWithListeners.size(); --i >= 0;)
+ {
+ ValueTree* const v = valueTreesWithListeners[i];
+ if (v != 0)
+ v->listeners.call (&ValueTree::Listener::valueTreeChildRemoved, tree, child);
+ }
+}
+
+void ValueTree::SharedObject::sendChildRemovedMessage (ValueTree child)
+{
+ ValueTree tree (this);
+ ValueTree::SharedObject* t = this;
+
+ while (t != 0)
+ {
+ t->sendChildRemovedMessage (tree, child);
+ t = t->parent;
+ }
+}
+
+void ValueTree::SharedObject::sendChildOrderChangedMessage (ValueTree& tree)
+{
+ for (int i = valueTreesWithListeners.size(); --i >= 0;)
+ {
+ ValueTree* const v = valueTreesWithListeners[i];
+ if (v != 0)
+ v->listeners.call (&ValueTree::Listener::valueTreeChildOrderChanged, tree);
+ }
+}
+
+void ValueTree::SharedObject::sendChildOrderChangedMessage()
+{
+ ValueTree tree (this);
+ ValueTree::SharedObject* t = this;
+
+ while (t != 0)
+ {
+ t->sendChildOrderChangedMessage (tree);
t = t->parent;
}
}
@@ -434,7 +478,7 @@ void ValueTree::SharedObject::addChild (SharedObject* child, int index, UndoMana
{
children.insert (index, child);
child->parent = this;
- sendChildChangeMessage();
+ sendChildAddedMessage (ValueTree (child));
child->sendParentChangeMessage();
}
else
@@ -464,7 +508,7 @@ void ValueTree::SharedObject::removeChild (const int childIndex, UndoManager* co
{
children.remove (childIndex);
child->parent = 0;
- sendChildChangeMessage();
+ sendChildRemovedMessage (ValueTree (child));
child->sendParentChangeMessage();
}
else
@@ -491,7 +535,7 @@ void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoMan
if (undoManager == 0)
{
children.move (currentIndex, newIndex);
- sendChildChangeMessage();
+ sendChildOrderChangedMessage();
}
else
{
@@ -510,16 +554,19 @@ void ValueTree::SharedObject::reorderChildren (const ReferenceCountedArray = 0);
+ moveChild (oldIndex, i, undoManager);
}
}
}
@@ -719,8 +766,10 @@ public:
sendChangeMessage (false);
}
- void valueTreeChildrenChanged (ValueTree&) {}
- void valueTreeParentChanged (ValueTree&) {}
+ void valueTreeChildAdded (ValueTree&, ValueTree&) {}
+ void valueTreeChildRemoved (ValueTree&, ValueTree&) {}
+ void valueTreeChildOrderChanged (ValueTree&) {}
+ void valueTreeParentChanged (ValueTree&) {}
private:
ValueTree tree;
diff --git a/src/containers/juce_ValueTree.h b/src/containers/juce_ValueTree.h
index b0a169c2b4..177342874e 100644
--- a/src/containers/juce_ValueTree.h
+++ b/src/containers/juce_ValueTree.h
@@ -368,16 +368,34 @@ public:
virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged,
const Identifier& property) = 0;
- /** This method is called when a child sub-tree is added or removed.
-
- The tree parameter indicates the tree whose child was added or removed.
+ /** This method is called when a child sub-tree is added.
Note that when you register a listener to a tree, it will receive this callback for
- child changes in that tree, and also in any of its children, (recursively, at any depth).
+ child changes in both that tree and any of its children, (recursively, at any depth).
If your tree has sub-trees but you only want to know about changes to the top level tree,
- simply check the tree parameter in this callback to make sure it's the tree you're interested in.
+ just check the parentTree parameter to make sure it's the one that you're interested in.
*/
- virtual void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged) = 0;
+ virtual void valueTreeChildAdded (ValueTree& parentTree,
+ ValueTree& childWhichHasBeenAdded) = 0;
+
+ /** This method is called when a child sub-tree is removed.
+
+ Note that when you register a listener to a tree, it will receive this callback for
+ child changes in both that tree and any of its children, (recursively, at any depth).
+ If your tree has sub-trees but you only want to know about changes to the top level tree,
+ just check the parentTree parameter to make sure it's the one that you're interested in.
+ */
+ virtual void valueTreeChildRemoved (ValueTree& parentTree,
+ ValueTree& childWhichHasBeenRemoved) = 0;
+
+ /** This method is called when a tree's children have been re-shuffled.
+
+ Note that when you register a listener to a tree, it will receive this callback for
+ child changes in both that tree and any of its children, (recursively, at any depth).
+ If your tree has sub-trees but you only want to know about changes to the top level tree,
+ just check the parameter to make sure it's the tree that you're interested in.
+ */
+ virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved) = 0;
/** This method is called when a tree has been added or removed from a parent node.
@@ -470,8 +488,12 @@ private:
void sendPropertyChangeMessage (const Identifier& property);
void sendPropertyChangeMessage (ValueTree& tree, const Identifier& property);
- void sendChildChangeMessage();
- void sendChildChangeMessage (ValueTree& tree);
+ void sendChildAddedMessage (ValueTree& parent, ValueTree& child);
+ void sendChildAddedMessage (ValueTree child);
+ void sendChildRemovedMessage (ValueTree& parent, ValueTree& child);
+ void sendChildRemovedMessage (ValueTree child);
+ void sendChildOrderChangedMessage (ValueTree& parent);
+ void sendChildOrderChangedMessage();
void sendParentChangeMessage();
const var& getProperty (const Identifier& name) const;
const var getProperty (const Identifier& name, const var& defaultReturnValue) const;
diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h
index c59a4a102b..474e199530 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 21
+#define JUCE_BUILDNUMBER 23
/** Current Juce version number.
diff --git a/src/gui/components/buttons/juce_DrawableButton.cpp b/src/gui/components/buttons/juce_DrawableButton.cpp
index ae7bec5fcd..38aca24e22 100644
--- a/src/gui/components/buttons/juce_DrawableButton.cpp
+++ b/src/gui/components/buttons/juce_DrawableButton.cpp
@@ -180,6 +180,7 @@ void DrawableButton::buttonStateChanged()
if (currentImage != 0)
{
+ currentImage->setInterceptsMouseClicks (false, false);
addAndMakeVisible (currentImage);
DrawableButton::resized();
}
diff --git a/src/gui/components/controls/juce_TextEditor.cpp b/src/gui/components/controls/juce_TextEditor.cpp
index 95a9fe78e8..848f5f0762 100644
--- a/src/gui/components/controls/juce_TextEditor.cpp
+++ b/src/gui/components/controls/juce_TextEditor.cpp
@@ -2621,5 +2621,9 @@ void TextEditor::coalesceSimilarSections()
}
}
+void TextEditor::Listener::textEditorTextChanged (TextEditor&) {}
+void TextEditor::Listener::textEditorReturnKeyPressed (TextEditor&) {}
+void TextEditor::Listener::textEditorEscapeKeyPressed (TextEditor&) {}
+void TextEditor::Listener::textEditorFocusLost (TextEditor&) {}
END_JUCE_NAMESPACE
diff --git a/src/gui/components/controls/juce_TextEditor.h b/src/gui/components/controls/juce_TextEditor.h
index 69444b6f1d..77fb6f3e0b 100644
--- a/src/gui/components/controls/juce_TextEditor.h
+++ b/src/gui/components/controls/juce_TextEditor.h
@@ -313,16 +313,16 @@ public:
virtual ~Listener() {}
/** Called when the user changes the text in some way. */
- virtual void textEditorTextChanged (TextEditor& editor) = 0;
+ virtual void textEditorTextChanged (TextEditor& editor);
/** Called when the user presses the return key. */
- virtual void textEditorReturnKeyPressed (TextEditor& editor) = 0;
+ virtual void textEditorReturnKeyPressed (TextEditor& editor);
/** Called when the user presses the escape key. */
- virtual void textEditorEscapeKeyPressed (TextEditor& editor) = 0;
+ virtual void textEditorEscapeKeyPressed (TextEditor& editor);
/** Called when the text editor loses focus. */
- virtual void textEditorFocusLost (TextEditor& editor) = 0;
+ virtual void textEditorFocusLost (TextEditor& editor);
};
/** Registers a listener to be told when things happen to the text.
diff --git a/src/gui/components/layout/juce_ComponentBuilder.cpp b/src/gui/components/layout/juce_ComponentBuilder.cpp
index 6dfc19c493..e616d22f22 100644
--- a/src/gui/components/layout/juce_ComponentBuilder.cpp
+++ b/src/gui/components/layout/juce_ComponentBuilder.cpp
@@ -201,7 +201,17 @@ void ComponentBuilder::valueTreePropertyChanged (ValueTree& tree, const Identifi
ComponentBuilderHelpers::updateComponent (*this, tree);
}
-void ComponentBuilder::valueTreeChildrenChanged (ValueTree& tree)
+void ComponentBuilder::valueTreeChildAdded (ValueTree& tree, ValueTree&)
+{
+ ComponentBuilderHelpers::updateComponent (*this, tree);
+}
+
+void ComponentBuilder::valueTreeChildRemoved (ValueTree& tree, ValueTree&)
+{
+ ComponentBuilderHelpers::updateComponent (*this, tree);
+}
+
+void ComponentBuilder::valueTreeChildOrderChanged (ValueTree& tree)
{
ComponentBuilderHelpers::updateComponent (*this, tree);
}
diff --git a/src/gui/components/layout/juce_ComponentBuilder.h b/src/gui/components/layout/juce_ComponentBuilder.h
index 17acbf34f9..3d56c8603c 100644
--- a/src/gui/components/layout/juce_ComponentBuilder.h
+++ b/src/gui/components/layout/juce_ComponentBuilder.h
@@ -229,7 +229,11 @@ public:
/** @internal */
void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property);
/** @internal */
- void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged);
+ void valueTreeChildAdded (ValueTree& parentTree, ValueTree& childWhichHasBeenAdded);
+ /** @internal */
+ void valueTreeChildRemoved (ValueTree& parentTree, ValueTree& childWhichHasBeenRemoved);
+ /** @internal */
+ void valueTreeChildOrderChanged (ValueTree& parentTree);
/** @internal */
void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged);
diff --git a/src/gui/components/menus/juce_PopupMenu.cpp b/src/gui/components/menus/juce_PopupMenu.cpp
index fb37eb91cd..f91ffa803a 100644
--- a/src/gui/components/menus/juce_PopupMenu.cpp
+++ b/src/gui/components/menus/juce_PopupMenu.cpp
@@ -135,17 +135,21 @@ class PopupMenu::ItemComponent : public Component
{
public:
//==============================================================================
- ItemComponent (const PopupMenu::Item& itemInfo_, int standardItemHeight)
+ ItemComponent (const PopupMenu::Item& itemInfo_, int standardItemHeight, Component* const parent)
: itemInfo (itemInfo_),
isHighlighted (false)
{
if (itemInfo.customComp != 0)
addAndMakeVisible (itemInfo.customComp);
+ parent->addAndMakeVisible (this);
+
int itemW = 80;
int itemH = 16;
getIdealSize (itemW, itemH, standardItemHeight);
setSize (itemW, jlimit (2, 600, itemH));
+
+ addMouseListener (parent, false);
}
~ItemComponent()
@@ -277,12 +281,7 @@ public:
setOpaque (getLookAndFeel().findColour (PopupMenu::backgroundColourId).isOpaque() || ! Desktop::canUseSemiTransparentWindows());
for (int i = 0; i < menu.items.size(); ++i)
- {
- PopupMenu::ItemComponent* const itemComp = new PopupMenu::ItemComponent (*menu.items.getUnchecked(i), standardItemHeight);
- items.add (itemComp);
- addAndMakeVisible (itemComp);
- itemComp->addMouseListener (this, false);
- }
+ items.add (new PopupMenu::ItemComponent (*menu.items.getUnchecked(i), standardItemHeight, this));
calculateWindowPos (target, alignToRectangle);
setTopLeftPosition (windowPos.getX(), windowPos.getY());
diff --git a/src/gui/graphics/drawables/juce_DrawableShape.cpp b/src/gui/graphics/drawables/juce_DrawableShape.cpp
index 4b0a479a72..32ae271f12 100644
--- a/src/gui/graphics/drawables/juce_DrawableShape.cpp
+++ b/src/gui/graphics/drawables/juce_DrawableShape.cpp
@@ -198,6 +198,12 @@ const Rectangle DrawableShape::getDrawableBounds() const
bool DrawableShape::hitTest (int x, int y)
{
+ bool allowsClicksOnThisComponent, allowsClicksOnChildComponents;
+ getInterceptsMouseClicks (allowsClicksOnThisComponent, allowsClicksOnChildComponents);
+
+ if (! allowsClicksOnThisComponent)
+ return false;
+
const float globalX = (float) (x - originRelativeToComponent.getX());
const float globalY = (float) (y - originRelativeToComponent.getY());
diff --git a/src/juce_core_includes.h b/src/juce_core_includes.h
index 8b058b01a5..827013e991 100644
--- a/src/juce_core_includes.h
+++ b/src/juce_core_includes.h
@@ -233,6 +233,9 @@
#ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__
#include "text/juce_CharacterFunctions.h"
#endif
+#ifndef __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
+ #include "text/juce_CharPointer_ASCII.h"
+#endif
#ifndef __JUCE_CHARPOINTER_UTF16_JUCEHEADER__
#include "text/juce_CharPointer_UTF16.h"
#endif
diff --git a/src/native/mac/juce_mac_Files.mm b/src/native/mac/juce_mac_Files.mm
index 2ae784b6e6..e6df621fc6 100644
--- a/src/native/mac/juce_mac_Files.mm
+++ b/src/native/mac/juce_mac_Files.mm
@@ -92,7 +92,7 @@ namespace FileHelpers
FSRef ref;
LSItemInfoRecord info;
- return FSPathMakeRefWithOptions ((const UInt8*) path.toUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
+ return FSPathMakeRefWithOptions ((const UInt8*) path.toUTF8().getAddress(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
&& (info.flags & kLSItemInfoIsInvisible) != 0;
#endif
diff --git a/src/native/windows/juce_win32_Misc.cpp b/src/native/windows/juce_win32_Misc.cpp
index 90966329e6..ad1aefbb4f 100644
--- a/src/native/windows/juce_win32_Misc.cpp
+++ b/src/native/windows/juce_win32_Misc.cpp
@@ -35,7 +35,7 @@ void SystemClipboard::copyTextToClipboard (const String& text)
{
if (EmptyClipboard() != 0)
{
- const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
+ const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer()) + 4;
if (bytesNeeded > 0)
{
diff --git a/src/text/juce_CharPointer_ASCII.h b/src/text/juce_CharPointer_ASCII.h
new file mode 100644
index 0000000000..569bd11c45
--- /dev/null
+++ b/src/text/juce_CharPointer_ASCII.h
@@ -0,0 +1,382 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-10 by Raw Material Software Ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the GNU General
+ Public License (Version 2), as published by the Free Software Foundation.
+ A copy of the license is included in the JUCE distribution, or can be found
+ online at www.gnu.org/licenses.
+
+ JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ ------------------------------------------------------------------------------
+
+ To release a closed-source product which uses JUCE, commercial licenses are
+ available: visit www.rawmaterialsoftware.com/juce for more information.
+
+ ==============================================================================
+*/
+
+#ifndef __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
+#define __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
+
+
+//==============================================================================
+/**
+ Wraps a pointer to a null-terminated ASCII character string, and provides
+ various methods to operate on the data.
+
+ A valid ASCII string is assumed to not contain any characters above 127.
+
+ @see CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
+*/
+class CharPointer_ASCII
+{
+public:
+ typedef char CharType;
+
+ inline explicit CharPointer_ASCII (const CharType* const rawPointer) throw()
+ : data (const_cast (rawPointer))
+ {
+ }
+
+ inline CharPointer_ASCII (const CharPointer_ASCII& other) throw()
+ : data (other.data)
+ {
+ }
+
+ inline CharPointer_ASCII& operator= (const CharPointer_ASCII& other) throw()
+ {
+ data = other.data;
+ return *this;
+ }
+
+ inline CharPointer_ASCII& operator= (const CharType* text) throw()
+ {
+ data = const_cast (text);
+ return *this;
+ }
+
+ /** 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;
+ }
+
+ /** Returns the address that this pointer is pointing to. */
+ inline CharType* getAddress() const throw() { return data; }
+
+ /** Returns the address that this pointer is pointing to. */
+ inline operator const CharType*() const throw() { return data; }
+
+ /** Returns true if this pointer is pointing to a null character. */
+ inline bool isEmpty() const throw() { return *data == 0; }
+
+ /** Returns the unicode character that this pointer is pointing to. */
+ inline juce_wchar operator*() const throw() { return *data; }
+
+ /** Moves this pointer along to the next character in the string. */
+ inline CharPointer_ASCII& operator++() throw()
+ {
+ ++data;
+ return *this;
+ }
+
+ /** Moves this pointer to the previous character in the string. */
+ inline CharPointer_ASCII& operator--() throw()
+ {
+ --data;
+ return *this;
+ }
+
+ /** Returns the character that this pointer is currently pointing to, and then
+ advances the pointer to point to the next character. */
+ inline juce_wchar getAndAdvance() throw() { return *data++; }
+
+ /** Moves this pointer along to the next character in the string. */
+ CharPointer_ASCII operator++ (int) throw()
+ {
+ CharPointer_ASCII temp (*this);
+ ++data;
+ return temp;
+ }
+
+ /** Moves this pointer forwards by the specified number of characters. */
+ inline void operator+= (const int numToSkip) throw()
+ {
+ data += numToSkip;
+ }
+
+ inline void operator-= (const int numToSkip) throw()
+ {
+ data -= numToSkip;
+ }
+
+ /** Returns the character at a given character index from the start of the string. */
+ inline juce_wchar operator[] (const int characterIndex) const throw()
+ {
+ return (juce_wchar) (unsigned char) data [characterIndex];
+ }
+
+ /** Returns a pointer which is moved forwards from this one by the specified number of characters. */
+ CharPointer_ASCII operator+ (const int numToSkip) const throw()
+ {
+ return CharPointer_ASCII (data + numToSkip);
+ }
+
+ /** Returns a pointer which is moved backwards from this one by the specified number of characters. */
+ CharPointer_ASCII operator- (const int numToSkip) const throw()
+ {
+ return CharPointer_ASCII (data - numToSkip);
+ }
+
+ /** Writes a unicode character to this string, and advances this pointer to point to the next position. */
+ inline void write (const juce_wchar charToWrite) throw()
+ {
+ *data++ = (char) charToWrite;
+ }
+
+ inline void replaceChar (const juce_wchar newChar) throw()
+ {
+ *data = (char) newChar;
+ }
+
+ /** Writes a null character to this string (leaving the pointer's position unchanged). */
+ inline void writeNull() const throw()
+ {
+ *data = 0;
+ }
+
+ /** Returns the number of characters in this string. */
+ size_t length() const throw()
+ {
+ return (size_t) strlen (data);
+ }
+
+ /** Returns the number of characters in this string, or the given value, whichever is lower. */
+ size_t lengthUpTo (const size_t maxCharsToCount) const throw()
+ {
+ return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
+ }
+
+ /** Returns the number of bytes that are used to represent this string.
+ This includes the terminating null character.
+ */
+ size_t sizeInBytes() const throw()
+ {
+ return length() + 1;
+ }
+
+ /** Returns the number of bytes that would be needed to represent the given
+ unicode character in this encoding format.
+ */
+ static inline size_t getBytesRequiredFor (const juce_wchar) throw()
+ {
+ return 1;
+ }
+
+ /** Returns the number of bytes that would be needed to represent the given
+ string in this encoding format.
+ The value returned does NOT include the terminating null character.
+ */
+ template
+ static size_t getBytesRequiredFor (const CharPointer& text) throw()
+ {
+ return text.length();
+ }
+
+ /** Returns a pointer to the null character that terminates this string. */
+ CharPointer_ASCII findTerminatingNull() const throw()
+ {
+ return CharPointer_ASCII (data + length());
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes. */
+ template
+ void writeAll (const CharPointer& src) throw()
+ {
+ CharacterFunctions::copyAll (*this, src);
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes. */
+ void writeAll (const CharPointer_ASCII& src) throw()
+ {
+ strcpy (data, src.data);
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes.
+ The maxDestBytes parameter specifies the maximum number of bytes that can be written
+ to the destination buffer before stopping.
+ */
+ template
+ int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw()
+ {
+ return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
+ }
+
+ /** Copies a source string to this pointer, advancing this pointer as it goes.
+ The maxChars parameter specifies the maximum number of characters that can be
+ written to the destination buffer before stopping (including the terminating null).
+ */
+ template
+ void writeWithCharLimit (const CharPointer& src, const int maxChars) throw()
+ {
+ CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
+ }
+
+ /** Compares this string with another one. */
+ template
+ int compare (const CharPointer& other) const throw()
+ {
+ return CharacterFunctions::compare (*this, other);
+ }
+
+ /** Compares this string with another one. */
+ int compare (const CharPointer_ASCII& other) const throw()
+ {
+ return strcmp (data, other.data);
+ }
+
+ /** Compares this string with another one, up to a specified number of characters. */
+ template
+ int compareUpTo (const CharPointer& other, const int maxChars) const throw()
+ {
+ return CharacterFunctions::compareUpTo (*this, other, maxChars);
+ }
+
+ /** Compares this string with another one, up to a specified number of characters. */
+ int compareUpTo (const CharPointer_ASCII& other, const int maxChars) const throw()
+ {
+ return strncmp (data, other.data, (size_t) maxChars);
+ }
+
+ /** Compares this string with another one. */
+ template
+ int compareIgnoreCase (const CharPointer& other) const
+ {
+ return CharacterFunctions::compareIgnoreCase (*this, other);
+ }
+
+ int compareIgnoreCase (const CharPointer_ASCII& other) const
+ {
+ #if JUCE_WINDOWS
+ return stricmp (data, other.data);
+ #else
+ return strcasecmp (data, other.data);
+ #endif
+ }
+
+ /** Compares this string with another one, up to a specified number of characters. */
+ template
+ int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw()
+ {
+ return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
+ }
+
+ /** Returns the character index of a substring, or -1 if it isn't found. */
+ template
+ int indexOf (const CharPointer& stringToFind) const throw()
+ {
+ return CharacterFunctions::indexOf (*this, stringToFind);
+ }
+
+ /** Returns the character index of a unicode character, or -1 if it isn't found. */
+ int indexOf (const juce_wchar charToFind) const throw()
+ {
+ int i = 0;
+
+ while (data[i] != 0)
+ {
+ if (data[i] == (char) charToFind)
+ return i;
+
+ ++i;
+ }
+
+ return -1;
+ }
+
+ /** Returns the character index of a unicode character, or -1 if it isn't found. */
+ int indexOf (const juce_wchar charToFind, const bool ignoreCase) const throw()
+ {
+ return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
+ : CharacterFunctions::indexOfChar (*this, charToFind);
+ }
+
+ /** Returns true if the first character of this string is whitespace. */
+ bool isWhitespace() const { return CharacterFunctions::isWhitespace (*data) != 0; }
+ /** Returns true if the first character of this string is a digit. */
+ bool isDigit() const { return CharacterFunctions::isDigit (*data) != 0; }
+ /** Returns true if the first character of this string is a letter. */
+ bool isLetter() const { return CharacterFunctions::isLetter (*data) != 0; }
+ /** Returns true if the first character of this string is a letter or digit. */
+ bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
+ /** Returns true if the first character of this string is upper-case. */
+ bool isUpperCase() const { return CharacterFunctions::isUpperCase (*data) != 0; }
+ /** Returns true if the first character of this string is lower-case. */
+ bool isLowerCase() const { return CharacterFunctions::isLowerCase (*data) != 0; }
+
+ /** Returns an upper-case version of the first character of this string. */
+ juce_wchar toUpperCase() const throw() { return CharacterFunctions::toUpperCase (*data); }
+ /** Returns a lower-case version of the first character of this string. */
+ juce_wchar toLowerCase() const throw() { return CharacterFunctions::toLowerCase (*data); }
+
+ /** Parses this string as a 32-bit integer. */
+ int getIntValue32() const throw() { return atoi (data); }
+
+ /** Parses this string as a 64-bit integer. */
+ int64 getIntValue64() const throw()
+ {
+ #if JUCE_LINUX || JUCE_ANDROID
+ return atoll (data);
+ #elif JUCE_WINDOWS
+ return _atoi64 (data);
+ #else
+ return CharacterFunctions::getIntValue (*this);
+ #endif
+ }
+
+ /** Parses this string as a floating point double. */
+ double getDoubleValue() const throw() { return CharacterFunctions::getDoubleValue (*this); }
+
+ /** Returns the first non-whitespace character in the string. */
+ CharPointer_ASCII findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 128;
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ while (--maxBytesToRead >= 0)
+ {
+ if (*dataToTest <= 0)
+ return *dataToTest == 0;
+
+ ++dataToTest;
+ }
+
+ return true;
+ }
+
+private:
+ CharType* data;
+};
+
+
+#endif // __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
diff --git a/src/text/juce_CharPointer_UTF16.h b/src/text/juce_CharPointer_UTF16.h
index db7f2c3865..fbba22c72f 100644
--- a/src/text/juce_CharPointer_UTF16.h
+++ b/src/text/juce_CharPointer_UTF16.h
@@ -395,6 +395,43 @@ public:
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF16 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 0x10ffff
+ && (((unsigned int) character) < 0xd800 || ((unsigned int) character) > 0xdfff);
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ maxBytesToRead /= sizeof (CharType);
+
+ while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ {
+ const uint32 n = (uint32) (uint16) *dataToTest++;
+
+ if (n >= 0xd800)
+ {
+ if (n > 0x10ffff)
+ return false;
+
+ if (n <= 0xdfff)
+ {
+ if (n > 0xdc00)
+ return false;
+
+ const uint32 nextChar = (uint32) (uint16) *dataToTest++;
+
+ if (nextChar < 0xdc00 || nextChar > 0xdfff)
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
/** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */
enum
{
diff --git a/src/text/juce_CharPointer_UTF32.h b/src/text/juce_CharPointer_UTF32.h
index 2e2926286c..a6872e89a7 100644
--- a/src/text/juce_CharPointer_UTF32.h
+++ b/src/text/juce_CharPointer_UTF32.h
@@ -106,7 +106,7 @@ public:
CharPointer_UTF32 operator++ (int) throw()
{
CharPointer_UTF32 temp (*this);
- ++*this;
+ ++data;
return temp;
}
@@ -341,6 +341,25 @@ public:
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF32 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 0x10ffff;
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ maxBytesToRead /= sizeof (CharType);
+
+ while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ if (! canRepresent (*dataToTest++))
+ return false;
+
+ return true;
+ }
+
+ /** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF32 atomicSwap (const CharPointer_UTF32& newValue)
{
return CharPointer_UTF32 (reinterpret_cast &> (data).exchange (newValue.data));
diff --git a/src/text/juce_CharPointer_UTF8.h b/src/text/juce_CharPointer_UTF8.h
index 33f1bec346..53b84854e1 100644
--- a/src/text/juce_CharPointer_UTF8.h
+++ b/src/text/juce_CharPointer_UTF8.h
@@ -88,9 +88,9 @@ public:
if (byte >= 0)
return byte;
- juce_wchar n = byte;
- juce_wchar mask = 0x7f;
- juce_wchar bit = 0x40;
+ uint32 n = (uint32) (uint8) byte;
+ uint32 mask = 0x7f;
+ uint32 bit = 0x40;
size_t numExtraValues = 0;
while ((n & bit) != 0 && bit > 0x10)
@@ -113,7 +113,7 @@ public:
n |= (nextByte & 0x3f);
}
- return n;
+ return (juce_wchar) n;
}
/** Moves this pointer along to the next character in the string. */
@@ -473,6 +473,51 @@ public:
/** Returns the first non-whitespace character in the string. */
CharPointer_UTF8 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); }
+ /** Returns true if the given unicode character can be represented in this encoding. */
+ static bool canRepresent (juce_wchar character) throw()
+ {
+ return ((unsigned int) character) < (unsigned int) 0x10ffff;
+ }
+
+ /** Returns true if this data contains a valid string in this encoding. */
+ static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
+ {
+ while (--maxBytesToRead >= 0 && *dataToTest != 0)
+ {
+ const char byte = *dataToTest;
+
+ if (byte < 0)
+ {
+ uint32 n = (uint32) (uint8) byte;
+ uint32 mask = 0x7f;
+ uint32 bit = 0x40;
+ int numExtraValues = 0;
+
+ while ((n & bit) != 0)
+ {
+ if (bit <= 0x10)
+ return false;
+
+ mask >>= 1;
+ ++numExtraValues;
+ bit >>= 1;
+ }
+
+ n &= mask;
+
+ while (--numExtraValues >= 0)
+ {
+ const uint32 nextByte = (uint32) (uint8) *dataToTest++;
+
+ if ((nextByte & 0xc0) != 0x80)
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
/** These values are the byte-order-mark (BOM) values for a UTF-8 stream. */
enum
{
diff --git a/src/text/juce_CharacterFunctions.cpp b/src/text/juce_CharacterFunctions.cpp
index a89fe8600d..cdab05eea4 100644
--- a/src/text/juce_CharacterFunctions.cpp
+++ b/src/text/juce_CharacterFunctions.cpp
@@ -40,6 +40,7 @@
BEGIN_JUCE_NAMESPACE
#include "juce_String.h"
+#include "../memory/juce_HeapBlock.h"
//==============================================================================
juce_wchar CharacterFunctions::toUpperCase (const juce_wchar character) throw()
diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp
index 1cf151e4fa..54c91f21c6 100644
--- a/src/text/juce_String.cpp
+++ b/src/text/juce_String.cpp
@@ -250,8 +250,41 @@ String::String (const String& stringToCopy, const size_t charsToAllocate)
}
String::String (const char* const t)
- : text (StringHolder::createFromCharPointer (CharPointer_UTF8 (t)))
+ : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t)))
{
+ /* If you get an assertion here, then you're trying to create a string from 8-bit data
+ that contains values greater than 127. These can NOT be correctly converted to unicode
+ because there's no way for the String class to know what encoding was used to
+ create them. The source data could be UTF-8, ASCII or one of many local code-pages.
+
+ To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
+ string to the String class - so for example if your source data is actually UTF-8,
+ you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
+ correctly convert the multi-byte characters to unicode. It's *highly* recommended that
+ you use UTF-8 with escape characters in your source code to represent extended characters,
+ because there's no other way to represent these strings in a way that isn't dependent on
+ the compiler, source code editor and platform.
+ */
+ jassert (CharPointer_ASCII::isValidString (t, std::numeric_limits::max()));
+}
+
+String::String (const char* const t, const size_t maxChars)
+ : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t), maxChars))
+{
+ /* If you get an assertion here, then you're trying to create a string from 8-bit data
+ that contains values greater than 127. These can NOT be correctly converted to unicode
+ because there's no way for the String class to know what encoding was used to
+ create them. The source data could be UTF-8, ASCII or one of many local code-pages.
+
+ To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
+ string to the String class - so for example if your source data is actually UTF-8,
+ you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
+ correctly convert the multi-byte characters to unicode. It's *highly* recommended that
+ you use UTF-8 with escape characters in your source code to represent extended characters,
+ because there's no other way to represent these strings in a way that isn't dependent on
+ the compiler, source code editor and platform.
+ */
+ jassert (CharPointer_ASCII::isValidString (t, (int) maxChars));
}
String::String (const juce_wchar* const t)
@@ -259,6 +292,11 @@ String::String (const juce_wchar* const t)
{
}
+String::String (const juce_wchar* const t, const size_t maxChars)
+ : text (StringHolder::createFromCharPointer (CharPointer_UTF32 (t), maxChars))
+{
+}
+
String::String (const CharPointer_UTF8& t)
: text (StringHolder::createFromCharPointer (t))
{
@@ -279,6 +317,11 @@ String::String (const CharPointer_UTF32& t, const size_t maxChars)
{
}
+String::String (const CharPointer_ASCII& t)
+ : text (StringHolder::createFromCharPointer (t))
+{
+}
+
#if JUCE_WINDOWS
String::String (const wchar_t* const t)
: text (StringHolder::createFromCharPointer (CharPointer_UTF16 (t)))
@@ -291,16 +334,6 @@ String::String (const wchar_t* const t, size_t maxChars)
}
#endif
-String::String (const char* const t, const size_t maxChars)
- : text (StringHolder::createFromCharPointer (CharPointer_UTF8 (t), maxChars))
-{
-}
-
-String::String (const juce_wchar* const t, const size_t maxChars)
- : text (StringHolder::createFromCharPointer (CharPointer_UTF32 (t), maxChars))
-{
-}
-
const String String::charToString (const juce_wchar character)
{
String result (Preallocation (1));
@@ -679,7 +712,7 @@ String& String::operator+= (const juce_wchar ch)
}
#if JUCE_WINDOWS
-String& String::operator+= (wchar_t ch)
+String& String::operator+= (const wchar_t ch)
{
return operator+= ((juce_wchar) ch);
}
diff --git a/src/text/juce_String.h b/src/text/juce_String.h
index 1cdf9dc477..1cef9b0822 100644
--- a/src/text/juce_String.h
+++ b/src/text/juce_String.h
@@ -37,6 +37,7 @@
#include "juce_CharPointer_UTF8.h"
#include "juce_CharPointer_UTF16.h"
#include "juce_CharPointer_UTF32.h"
+#include "juce_CharPointer_ASCII.h"
#if JUCE_MSVC
#pragma warning (pop)
@@ -60,7 +61,6 @@ class JUCE_API String
public:
//==============================================================================
/** Creates an empty string.
-
@see empty
*/
String() throw();
@@ -68,15 +68,36 @@ public:
/** Creates a copy of another string. */
String (const String& other) throw();
- /** Creates a string from a zero-terminated text string.
- The string is assumed to be stored in the default system encoding.
+ /** Creates a string from a zero-terminated ascii text string.
+
+ The string passed-in must not contain any characters with a value above 127, because
+ these can't be converted to unicode without knowing the original encoding that was
+ used to create the string. If you attempt to pass-in values above 127, you'll get an
+ assertion.
+
+ To create strings with extended characters from UTF-8, you should explicitly call
+ String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
+ use UTF-8 with escape characters in your source code to represent extended characters,
+ because there's no other way to represent unicode strings in a way that isn't dependent
+ on the compiler, source code editor and platform.
*/
String (const char* text);
- /** Creates a string from an string of characters.
+ /** Creates a string from a string of 8-bit ascii characters.
- This will use up the the first maxChars characters of the string (or
- less if the string is actually shorter)
+ The string passed-in must not contain any characters with a value above 127, because
+ these can't be converted to unicode without knowing the original encoding that was
+ used to create the string. If you attempt to pass-in values above 127, you'll get an
+ assertion.
+
+ To create strings with extended characters from UTF-8, you should explicitly call
+ String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
+ use UTF-8 with escape characters in your source code to represent extended characters,
+ because there's no other way to represent unicode strings in a way that isn't dependent
+ on the compiler, source code editor and platform.
+
+ This will use up the the first maxChars characters of the string (or less if the string
+ is actually shorter).
*/
String (const char* text, size_t maxChars);
@@ -102,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 an ASCII character string */
+ String (const CharPointer_ASCII& text);
+
#if JUCE_WINDOWS
/** Creates a string from a UTF-16 character string */
String (const wchar_t* text);
diff --git a/src/text/juce_XmlDocument.cpp b/src/text/juce_XmlDocument.cpp
index f1e8868a9d..de7dbcfd55 100644
--- a/src/text/juce_XmlDocument.cpp
+++ b/src/text/juce_XmlDocument.cpp
@@ -124,7 +124,7 @@ XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentEle
}
}
- input = static_cast (textToParse);
+ input = textToParse.getCharPointer();
lastError = String::empty;
errorOccurred = false;
outOfData = false;
@@ -235,7 +235,7 @@ void XmlDocument::skipHeader()
return;
input += docTypeIndex + 9;
- const CharPointer_UTF32 docType (input);
+ const String::CharPointerType docType (input);
int n = 1;
@@ -324,7 +324,7 @@ void XmlDocument::readQuotedString (String& result)
else
{
--input;
- const CharPointer_UTF32 start (input);
+ const String::CharPointerType start (input);
for (;;)
{
@@ -332,14 +332,14 @@ void XmlDocument::readQuotedString (String& result)
if (character == quote)
{
- result.append (start.getAddress(), (int) (input.getAddress() - start.getAddress()));
+ result.appendCharPointer (start, (int) (input.getAddress() - start.getAddress()));
++input;
return;
}
else if (character == '&')
{
- result.append (start.getAddress(), (int) (input.getAddress() - start.getAddress()));
+ result.appendCharPointer (start, (int) (input.getAddress() - start.getAddress()));
break;
}
else if (character == 0)
@@ -419,7 +419,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
if (attNameLen > 0)
{
- const CharPointer_UTF32 attNameStart (input);
+ const String::CharPointerType attNameStart (input);
input += attNameLen;
skipNextWhiteSpace();
@@ -462,7 +462,7 @@ void XmlDocument::readChildElements (XmlElement* parent)
for (;;)
{
- const CharPointer_UTF32 preWhitespaceInput (input);
+ const String::CharPointerType preWhitespaceInput (input);
skipNextWhiteSpace();
if (outOfData)
@@ -493,7 +493,7 @@ void XmlDocument::readChildElements (XmlElement* parent)
&& input[8] == '[')
{
input += 9;
- const CharPointer_UTF32 inputStart (input);
+ const String::CharPointerType inputStart (input);
int len = 0;
@@ -556,10 +556,10 @@ void XmlDocument::readChildElements (XmlElement* parent)
if (entity.startsWithChar ('<') && entity [1] != 0)
{
- const CharPointer_UTF32 oldInput (input);
+ const String::CharPointerType oldInput (input);
const bool oldOutOfData = outOfData;
- input = static_cast (entity);
+ input = entity.getCharPointer();
outOfData = false;
for (;;)
@@ -582,7 +582,7 @@ void XmlDocument::readChildElements (XmlElement* parent)
}
else
{
- const CharPointer_UTF32 start (input);
+ const String::CharPointerType start (input);
int len = 0;
for (;;)
@@ -701,7 +701,7 @@ void XmlDocument::readEntity (String& result)
}
else
{
- const CharPointer_UTF32 entityNameStart (input);
+ const String::CharPointerType entityNameStart (input);
const int closingSemiColon = input.indexOf ((juce_wchar) ';');
if (closingSemiColon < 0)
diff --git a/src/text/juce_XmlDocument.h b/src/text/juce_XmlDocument.h
index 915451edb2..a43dc6447d 100644
--- a/src/text/juce_XmlDocument.h
+++ b/src/text/juce_XmlDocument.h
@@ -153,7 +153,7 @@ public:
//==============================================================================
private:
String originalText;
- CharPointer_UTF32 input;
+ String::CharPointerType input;
bool outOfData, errorOccurred;
String lastError, dtdText;