Browse Source

Many more String changes, so that finally the String class can store its internal data as either utf8, 16 or 32 - this is controlled by a flag JUCE_STRING_UTF_TYPE. It's currently set to utf-8 by default.

tags/2021-05-28
Julian Storer 14 years ago
parent
commit
533e7ba795
46 changed files with 970 additions and 683 deletions
  1. +1
    -1
      extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_XCode.h
  2. +1
    -1
      extras/Jucer (experimental)/Source/Project/jucer_ProjectExporter.h
  3. +19
    -19
      extras/audio plugin host/Source/MainHostWindow.cpp
  4. +1
    -1
      extras/audio plugins/demo/Source/PluginEditor.cpp
  5. +4
    -4
      extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp
  6. +10
    -10
      extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp
  7. +3
    -3
      extras/the jucer/src/model/jucer_BinaryResources.cpp
  8. +1
    -1
      extras/the jucer/src/utility/jucer_UtilityFunctions.cpp
  9. +1
    -1
      extras/the jucer/src/utility/jucer_UtilityFunctions.h
  10. +5
    -1
      src/audio/devices/juce_AudioDeviceManager.cpp
  11. +6
    -6
      src/audio/plugins/formats/juce_VSTPluginFormat.cpp
  12. +1
    -1
      src/core/juce_RelativeTime.cpp
  13. +1
    -1
      src/core/juce_StandardHeader.h
  14. +35
    -15
      src/core/juce_Time.cpp
  15. +6
    -5
      src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp
  16. +19
    -13
      src/gui/components/code_editor/juce_CodeDocument.cpp
  17. +26
    -12
      src/gui/components/code_editor/juce_CodeEditorComponent.cpp
  18. +34
    -32
      src/gui/components/controls/juce_TextEditor.cpp
  19. +1
    -1
      src/gui/components/juce_Component.cpp
  20. +1
    -1
      src/gui/components/windows/juce_ComponentPeer.cpp
  21. +14
    -5
      src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp
  22. +1
    -1
      src/gui/graphics/geometry/juce_Rectangle.h
  23. +19
    -11
      src/io/files/juce_File.cpp
  24. +0
    -1
      src/io/network/juce_MACAddress.cpp
  25. +1
    -1
      src/io/streams/juce_MemoryOutputStream.cpp
  26. +3
    -3
      src/memory/juce_MemoryBlock.cpp
  27. +1
    -9
      src/native/linux/juce_linux_Clipboard.cpp
  28. +2
    -2
      src/native/linux/juce_linux_Messaging.cpp
  29. +1
    -1
      src/native/linux/juce_linux_Midi.cpp
  30. +1
    -1
      src/native/linux/juce_linux_Threads.cpp
  31. +9
    -27
      src/native/mac/juce_mac_Strings.mm
  32. +2
    -0
      src/native/windows/juce_win32_Files.cpp
  33. +4
    -4
      src/native/windows/juce_win32_Network.cpp
  34. +5
    -4
      src/native/windows/juce_win32_Threads.cpp
  35. +40
    -3
      src/text/juce_CharPointer_UTF16.h
  36. +48
    -3
      src/text/juce_CharPointer_UTF8.h
  37. +0
    -18
      src/text/juce_CharacterFunctions.cpp
  38. +18
    -4
      src/text/juce_CharacterFunctions.h
  39. +2
    -2
      src/text/juce_Identifier.h
  40. +2
    -1
      src/text/juce_LocalisedStrings.cpp
  41. +491
    -342
      src/text/juce_String.cpp
  42. +113
    -96
      src/text/juce_String.h
  43. +5
    -5
      src/text/juce_StringArray.cpp
  44. +1
    -1
      src/text/juce_StringPool.cpp
  45. +1
    -1
      src/text/juce_StringPool.h
  46. +10
    -8
      src/text/juce_XmlDocument.cpp

+ 1
- 1
extras/Jucer (experimental)/Source/Project/jucer_ProjectExport_XCode.h View File

@@ -720,7 +720,7 @@ private:
for (int i = 0; i < objects.size(); ++i)
{
ValueTree& o = *objects.getUnchecked(i);
output << "\t\t" << static_cast <const juce_wchar*> (o.getType()) << " = { ";
output << "\t\t" << o.getType().toString() << " = { ";
for (int j = 0; j < o.getNumProperties(); ++j)
{


+ 1
- 1
extras/Jucer (experimental)/Source/Project/jucer_ProjectExporter.h View File

@@ -92,7 +92,7 @@ public:
const String getExporterIdentifierMacro() const
{
return "JUCER_" + settings.getType() + "_"
return "JUCER_" + settings.getType().toString() + "_"
+ String::toHexString (settings [Ids::targetFolder].toString().hashCode()).toUpperCase();
}


+ 19
- 19
extras/audio plugin host/Source/MainHostWindow.cpp View File

@@ -80,7 +80,7 @@ MainHostWindow::MainHostWindow()
DocumentWindow::allButtons)
{
XmlElement* const savedAudioState = ApplicationProperties::getInstance()->getUserSettings()
->getXmlValue (T("audioDeviceState"));
->getXmlValue ("audioDeviceState");
deviceManager.initialise (256, 256, savedAudioState, true);
@@ -101,7 +101,7 @@ MainHostWindow::MainHostWindow()
XmlElement* const savedPluginList = ApplicationProperties::getInstance()
->getUserSettings()
->getXmlValue (T("pluginList"));
->getXmlValue ("pluginList");
if (savedPluginList != 0)
{
@@ -110,7 +110,7 @@ MainHostWindow::MainHostWindow()
}
pluginSortMethod = (KnownPluginList::SortMethod) ApplicationProperties::getInstance()->getUserSettings()
->getIntValue (T("pluginSortMethod"), KnownPluginList::sortByManufacturer);
->getIntValue ("pluginSortMethod", KnownPluginList::sortByManufacturer);
knownPluginList.addChangeListener (this);
@@ -169,7 +169,7 @@ void MainHostWindow::changeListenerCallback (ChangeBroadcaster*)
if (savedPluginList != 0)
{
ApplicationProperties::getInstance()->getUserSettings()
->setValue (T("pluginList"), savedPluginList);
->setValue ("pluginList", savedPluginList);
delete savedPluginList;
@@ -199,7 +199,7 @@ const PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const St
PopupMenu recentFilesMenu;
recentFiles.createPopupMenuItems (recentFilesMenu, 100, true, true);
menu.addSubMenu (T("Open recent file"), recentFilesMenu);
menu.addSubMenu ("Open recent file", recentFilesMenu);
menu.addCommandItem (commandManager, CommandIDs::save);
menu.addCommandItem (commandManager, CommandIDs::saveAs);
@@ -211,9 +211,9 @@ const PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const St
// "Plugins" menu
PopupMenu pluginsMenu;
addPluginsToMenu (pluginsMenu);
menu.addSubMenu (T("Create plugin"), pluginsMenu);
menu.addSubMenu ("Create plugin", pluginsMenu);
menu.addSeparator();
menu.addItem (250, T("Delete all plugins"));
menu.addItem (250, "Delete all plugins");
}
else if (topLevelMenuIndex == 2)
@@ -272,7 +272,7 @@ void MainHostWindow::menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/
pluginSortMethod = KnownPluginList::sortByFileSystemLocation;
ApplicationProperties::getInstance()->getUserSettings()
->setValue (T("pluginSortMethod"), (int) pluginSortMethod);
->setValue ("pluginSortMethod", (int) pluginSortMethod);
}
else
{
@@ -339,34 +339,34 @@ void MainHostWindow::getCommandInfo (const CommandID commandID, ApplicationComma
switch (commandID)
{
case CommandIDs::open:
result.setInfo (T("Open..."),
T("Opens a filter graph file"),
result.setInfo ("Open...),
"Opens a filter graph file),
category, 0);
result.defaultKeypresses.add (KeyPress (T('o'), ModifierKeys::commandModifier, 0));
result.defaultKeypresses.add (KeyPress ('o), ModifierKeys::commandModifier, 0));
break;
case CommandIDs::save:
result.setInfo (T("Save"),
T("Saves the current graph to a file"),
result.setInfo ("Save",
"Saves the current graph to a file",
category, 0);
result.defaultKeypresses.add (KeyPress (T('s'), ModifierKeys::commandModifier, 0));
result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier, 0));
break;
case CommandIDs::saveAs:
result.setInfo (T("Save As..."),
T("Saves a copy of the current graph to a file"),
result.setInfo ("Save As...),
"Saves a copy of the current graph to a file",
category, 0);
result.defaultKeypresses.add (KeyPress (T('s'), ModifierKeys::shiftModifier | ModifierKeys::commandModifier, 0));
result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::shiftModifier | ModifierKeys::commandModifier, 0));
break;
case CommandIDs::showPluginListEditor:
result.setInfo ("Edit the list of available plug-Ins...", String::empty, category, 0);
result.addDefaultKeypress (T('p'), ModifierKeys::commandModifier);
result.addDefaultKeypress ('p', ModifierKeys::commandModifier);
break;
case CommandIDs::showAudioSettings:
result.setInfo ("Change the audio device settings", String::empty, category, 0);
result.addDefaultKeypress (T('a'), ModifierKeys::commandModifier);
result.addDefaultKeypress ('a', ModifierKeys::commandModifier);
break;
case CommandIDs::aboutBox:


+ 1
- 1
extras/audio plugins/demo/Source/PluginEditor.cpp View File

@@ -161,7 +161,7 @@ void JuceDemoPluginAudioProcessorEditor::displayPositionInfo (const AudioPlayHea
{
lastDisplayedPosition = pos;
String displayText;
displayText.preallocateStorage (64);
displayText.preallocateBytes (128);
displayText << String (pos.bpm, 2) << " bpm, "
<< pos.timeSigNumerator << '/' << pos.timeSigDenominator


+ 4
- 4
extras/audio plugins/wrapper/RTAS/juce_RTAS_Wrapper.cpp View File

@@ -885,7 +885,7 @@ private:
void GetNameOfLength (char* name, int maxLength, OSType inControllerType) const
{
juceFilter->getParameterName (index).copyToCString (name, maxLength);
juceFilter->getParameterName (index).copyToUTF8 (name, maxLength);
}
long GetPriority() const { return kFicCooperativeTaskPriority; }
@@ -900,7 +900,7 @@ private:
void GetValueString (char* valueString, int maxLength, long value) const
{
juceFilter->getParameterText (index).copyToCString (valueString, maxLength);
juceFilter->getParameterText (index).copyToUTF8 (valueString, maxLength);
}
Cmn_Bool IsAutomatable() const
@@ -925,7 +925,7 @@ public:
JucePlugInGroup()
{
DefineManufacturerNamesAndID (JucePlugin_Manufacturer, JucePlugin_RTASManufacturerCode);
DefinePlugInNamesAndVersion (createRTASName().toCString(), JucePlugin_VersionCode);
DefinePlugInNamesAndVersion (createRTASName().toUTF8(), JucePlugin_VersionCode);
#ifndef JUCE_DEBUG
AddGestalt (pluginGestalt_IsCacheable);
@@ -955,7 +955,7 @@ public:
JucePlugin_RTASProductId,
JucePlugin_RTASCategory);
type->DefineTypeNames (createRTASName().toCString());
type->DefineTypeNames (createRTASName().toUTF8().getAddress());
type->DefineSampleRateSupport (eSupports48kAnd96kAnd192k);
type->DefineStemFormats (getFormatForChans (channelConfigs [i][0] != 0 ? channelConfigs [i][0] : channelConfigs [i][1]),


+ 10
- 10
extras/audio plugins/wrapper/VST/juce_VST_Wrapper.cpp View File

@@ -410,13 +410,13 @@ public:
//==============================================================================
bool getEffectName (char* name)
{
String (JucePlugin_Name).copyToCString (name, 64);
String (JucePlugin_Name).copyToUTF8 (name, 64);
return true;
}
bool getVendorString (char* text)
{
String (JucePlugin_Manufacturer).copyToCString (text, 64);
String (JucePlugin_Manufacturer).copyToUTF8 (text, 64);
return true;
}
@@ -486,8 +486,8 @@ public:
const String name (filter->getInputChannelName ((int) index));
name.copyToCString (properties->label, kVstMaxLabelLen - 1);
name.copyToCString (properties->shortLabel, kVstMaxShortLabelLen - 1);
name.copyToUTF8 (properties->label, kVstMaxLabelLen - 1);
name.copyToUTF8 (properties->shortLabel, kVstMaxShortLabelLen - 1);
if (speakerIn != kSpeakerArrEmpty)
{
@@ -514,8 +514,8 @@ public:
const String name (filter->getOutputChannelName ((int) index));
name.copyToCString (properties->label, kVstMaxLabelLen - 1);
name.copyToCString (properties->shortLabel, kVstMaxShortLabelLen - 1);
name.copyToUTF8 (properties->label, kVstMaxLabelLen - 1);
name.copyToUTF8 (properties->shortLabel, kVstMaxShortLabelLen - 1);
if (speakerOut != kSpeakerArrEmpty)
{
@@ -851,14 +851,14 @@ public:
void getProgramName (char* name)
{
if (filter != 0)
filter->getProgramName (filter->getCurrentProgram()).copyToCString (name, 24);
filter->getProgramName (filter->getCurrentProgram()).copyToUTF8 (name, 24);
}
bool getProgramNameIndexed (VstInt32 /*category*/, VstInt32 index, char* text)
{
if (filter != 0 && isPositiveAndBelow (index, filter->getNumPrograms()))
{
filter->getProgramName (index).copyToCString (text, 24);
filter->getProgramName (index).copyToUTF8 (text, 24);
return true;
}
@@ -889,7 +889,7 @@ public:
if (filter != 0)
{
jassert (isPositiveAndBelow (index, filter->getNumParameters()));
filter->getParameterText (index).copyToCString (text, 24); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
filter->getParameterText (index).copyToUTF8 (text, 24); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
}
}
@@ -898,7 +898,7 @@ public:
if (filter != 0)
{
jassert (isPositiveAndBelow (index, filter->getNumParameters()));
filter->getParameterName (index).copyToCString (text, 16); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
filter->getParameterName (index).copyToUTF8 (text, 16); // length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
}
}


+ 3
- 3
extras/the jucer/src/model/jucer_BinaryResources.cpp View File

@@ -243,12 +243,12 @@ void BinaryResources::loadFromCpp (const File& cppFileLocation, const String& cp
.fromFirstOccurrenceOf (T("{"), false, false));
MemoryOutputStream out;
const juce_wchar* t = (const juce_wchar*) dataString;
String::CharPointerType t (dataString.getCharPointer());
int n = 0;
while (*t != 0)
while (! t.isEmpty())
{
const juce_wchar c = *t++;
const juce_wchar c = t.getAndAdvance();
if (c >= '0' && c <= '9')
n = n * 10 + (c - '0');


+ 1
- 1
extras/the jucer/src/utility/jucer_UtilityFunctions.cpp View File

@@ -33,7 +33,7 @@ const String replaceCEscapeChars (const String& s)
const int len = s.length();
String r;
r.preallocateStorage (len + 2);
r.preallocateBytes (4 * len + 4);
bool lastWasHexEscapeCode = false;
for (int i = 0; i < len; ++i)


+ 1
- 1
extras/the jucer/src/utility/jucer_UtilityFunctions.h View File

@@ -148,7 +148,7 @@ public:
const String toString() const throw()
{
String s;
s.preallocateStorage (12);
s.preallocateBytes (32);
addPosDescription (s, xMode, x); s << ' ';
addPosDescription (s, yMode, y); s << ' ';
addSizeDescription (s, wMode, w); s << ' ';


+ 5
- 1
src/audio/devices/juce_AudioDeviceManager.cpp View File

@@ -613,7 +613,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
{
const ScopedLock sl (audioCallbackLock);
if (inputLevelMeasurementEnabledCount > 0)
if (inputLevelMeasurementEnabledCount > 0 && numInputChannels > 0)
{
for (int j = 0; j < numSamples; ++j)
{
@@ -634,6 +634,10 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
inputLevel = 0;
}
}
else
{
inputLevel = 0;
}
if (callbacks.size() > 0)
{


+ 6
- 6
src/audio/plugins/formats/juce_VSTPluginFormat.cpp View File

@@ -483,7 +483,7 @@ public:
if (file.hasFileExtension (".vst"))
{
const char* const utf8 = filename.toUTF8();
const char* const utf8 = filename.toUTF8().getAddress();
CFURLRef url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*) utf8,
strlen (utf8), file.isDirectory());
@@ -2014,7 +2014,7 @@ void VSTPluginInstance::setParamsInProgramBlock (fxProgram* const prog)
prog->fxVersion = vst_swap (getVersionNumber());
prog->numParams = vst_swap (numParams);
getCurrentProgramName().copyToCString (prog->prgName, sizeof (prog->prgName) - 1);
getCurrentProgramName().copyToUTF8 (prog->prgName, sizeof (prog->prgName) - 1);
for (int i = 0; i < numParams; ++i)
prog->params[i] = vst_swapFloat (getParameter (i));
@@ -2065,7 +2065,7 @@ bool VSTPluginInstance::saveToFXBFile (MemoryBlock& dest, bool isFXB, int maxSiz
set->numPrograms = vst_swap (numPrograms);
set->chunkSize = vst_swap ((long) chunk.getSize());
getCurrentProgramName().copyToCString (set->name, sizeof (set->name) - 1);
getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1);
chunk.copyTo (set->chunk, 0, chunk.getSize());
}
}
@@ -2230,7 +2230,7 @@ namespace
if (JUCEApplication::getInstance() != 0)
hostName = JUCEApplication::getInstance()->getApplicationName();
hostName.copyToCString ((char*) ptr, jmin (kVstMaxVendorStrLen, kVstMaxProductStrLen) - 1);
hostName.copyToUTF8 ((char*) ptr, jmin (kVstMaxVendorStrLen, kVstMaxProductStrLen) - 1);
break;
}
@@ -2544,7 +2544,7 @@ void VSTPluginInstance::createTempParameterStore (MemoryBlock& dest)
dest.setSize (64 + 4 * getNumParameters());
dest.fillWith (0);
getCurrentProgramName().copyToCString ((char*) dest.getData(), 63);
getCurrentProgramName().copyToUTF8 ((char*) dest.getData(), 63);
float* const p = (float*) (((char*) dest.getData()) + 64);
for (int i = 0; i < getNumParameters(); ++i)
@@ -2594,7 +2594,7 @@ void VSTPluginInstance::changeProgramName (int index, const String& newName)
if (index == getCurrentProgram())
{
if (getNumPrograms() > 0 && newName != getCurrentProgramName())
dispatch (effSetProgramName, 0, 0, (void*) newName.substring (0, 24).toCString(), 0.0f);
dispatch (effSetProgramName, 0, 0, (void*) newName.substring (0, 24).toUTF8().getAddress(), 0.0f);
}
else
{


+ 1
- 1
src/core/juce_RelativeTime.cpp View File

@@ -68,7 +68,7 @@ const String RelativeTime::getDescription (const String& returnValueForZeroTime)
return returnValueForZeroTime;
String result;
result.preallocateStorage (16);
result.preallocateBytes (32);
if (seconds < 0)
result << '-';


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 35
#define JUCE_BUILDNUMBER 36
/** Current Juce version number.


+ 35
- 15
src/core/juce_Time.cpp View File

@@ -56,7 +56,7 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
namespace TimeHelpers
{
static struct tm millisToLocal (const int64 millis) throw()
struct tm millisToLocal (const int64 millis) throw()
{
struct tm result;
const int64 seconds = millis / 1000;
@@ -92,30 +92,51 @@ namespace TimeHelpers
{
time_t now = static_cast <time_t> (seconds);
#if JUCE_WINDOWS
#ifdef USE_NEW_SECURE_TIME_FNS
#if JUCE_WINDOWS
#ifdef USE_NEW_SECURE_TIME_FNS
if (now >= 0 && now <= 0x793406fff)
localtime_s (&result, &now);
else
zeromem (&result, sizeof (result));
#else
#else
result = *localtime (&now);
#endif
#else
// more thread-safe
localtime_r (&now, &result);
#endif
#endif
#else
localtime_r (&now, &result); // more thread-safe
#endif
}
return result;
}
static int extendedModulo (const int64 value, const int modulo) throw()
int extendedModulo (const int64 value, const int modulo) throw()
{
return (int) (value >= 0 ? (value % modulo)
: (value - ((value / modulo) + 1) * modulo));
}
int doFTime (juce_wchar* const dest, const int maxChars, const String& format, const struct tm* const tm) throw()
{
#if JUCE_ANDROID
HeapBlock <char> tempDest;
tempDest.calloc (maxChars + 2);
const int result = (int) strftime (tempDest, maxChars, format.toUTF8(), tm);
if (result > 0)
CharPointer_UTF32 (dest).writeAll (CharPointer_UTF8 (tempDest.getData()));
return result;
#elif JUCE_WINDOWS
HeapBlock <wchar_t> tempDest;
tempDest.calloc (maxChars + 2);
const int result = (int) wcsftime (tempDest, maxChars, format.toUTF16(), tm);
if (result > 0)
CharPointer_UTF32 (dest).writeAll (CharPointer_UTF16 (tempDest.getData()));
return result;
#else
return (int) wcsftime (dest, maxChars, format.toUTF32(), tm);
#endif
}
static uint32 lastMSCounterValue = 0;
}
@@ -342,19 +363,18 @@ const String Time::toString (const bool includeDate,
const String Time::formatted (const String& format) const
{
String buffer;
int bufferSize = 128;
buffer.preallocateStorage (bufferSize);
HeapBlock<juce_wchar> buffer (128);
struct tm t (TimeHelpers::millisToLocal (millisSinceEpoch));
while (CharacterFunctions::ftime (buffer.getCharPointer().getAddress(), bufferSize, format.getCharPointer(), &t) <= 0)
while (TimeHelpers::doFTime (buffer.getData(), bufferSize, format, &t) <= 0)
{
bufferSize += 128;
buffer.preallocateStorage (bufferSize);
buffer.malloc (bufferSize);
}
return buffer;
return String (buffer);
}
//==============================================================================


+ 6
- 5
src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp View File

@@ -115,23 +115,24 @@ namespace CppTokeniser
int parseIdentifier (CodeDocument::Iterator& source) throw()
{
int tokenLength = 0;
juce_wchar possibleIdentifier [19];
String::CharPointerType::CharType possibleIdentifier [100];
String::CharPointerType possible (possibleIdentifier);
while (isIdentifierBody (source.peekNextChar()))
{
const juce_wchar c = source.nextChar();
if (tokenLength < numElementsInArray (possibleIdentifier) - 1)
possibleIdentifier [tokenLength] = c;
if (tokenLength < 20)
possible.write (c);
++tokenLength;
}
if (tokenLength > 1 && tokenLength <= 16)
{
possibleIdentifier [tokenLength] = 0;
possible.writeNull();
if (isReservedKeyword (CharPointer_UTF32 (possibleIdentifier), tokenLength))
if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
return CPlusPlusCodeTokeniser::tokenType_builtInKeyword;
}


+ 19
- 13
src/gui/components/code_editor/juce_CodeDocument.cpp View File

@@ -28,6 +28,7 @@
BEGIN_JUCE_NAMESPACE
#include "juce_CodeDocument.h"
#include "../../../io/streams/juce_MemoryOutputStream.h"
//==============================================================================
@@ -107,13 +108,19 @@ public:
void updateLength() throw()
{
lineLengthWithoutNewLines = lineLength = line.length();
lineLength = 0;
lineLengthWithoutNewLines = 0;
while (lineLengthWithoutNewLines > 0
&& (line [lineLengthWithoutNewLines - 1] == '\n'
|| line [lineLengthWithoutNewLines - 1] == '\r'))
String::CharPointerType t (line.getCharPointer());
while (! t.isEmpty())
{
--lineLengthWithoutNewLines;
++lineLength;
const juce_wchar c = t.getAndAdvance();
if (c != '\n' && c != '\r')
lineLengthWithoutNewLines = lineLength;
}
}
@@ -201,7 +208,7 @@ void CodeDocument::Iterator::skipToEndOfLine()
juce_wchar CodeDocument::Iterator::peekNextChar() const
{
if (currentLine == 0)
if (currentLine == 0 || currentLine->line.isEmpty())
return 0;
jassert (currentLine == document->lines.getUnchecked (line));
@@ -481,9 +488,8 @@ const String CodeDocument::getTextBetween (const Position& start, const Position
return (line == 0) ? String::empty : line->line.substring (start.getIndexInLine(), end.getIndexInLine());
}
String result;
result.preallocateStorage (end.getPosition() - start.getPosition() + 4);
String::Concatenator concatenator (result);
MemoryOutputStream mo;
mo.preallocate (end.getPosition() - start.getPosition() + 4);
const int maxLine = jmin (lines.size() - 1, endLine);
@@ -495,20 +501,20 @@ const String CodeDocument::getTextBetween (const Position& start, const Position
if (i == startLine)
{
const int index = start.getIndexInLine();
concatenator.append (line->line.substring (index, len));
mo << line->line.substring (index, len);
}
else if (i == endLine)
{
len = end.getIndexInLine();
concatenator.append (line->line.substring (0, len));
mo << line->line.substring (0, len);
}
else
{
concatenator.append (line->line);
mo << line->line;
}
}
return result;
return mo.toString();
}
int CodeDocument::getNumCharacters() const throw()


+ 26
- 12
src/gui/components/code_editor/juce_CodeEditorComponent.cpp View File

@@ -260,10 +260,11 @@ private:
{
jassert (index <= line.length());
String::CharPointerType t (line.getCharPointer());
int col = 0;
for (int i = 0; i < index; ++i)
{
if (line[i] != '\t')
if (t.getAndAdvance() != '\t')
++col;
else
col += spacesPerTab - (col % spacesPerTab);
@@ -777,12 +778,18 @@ namespace CodeEditorHelpers
{
int findFirstNonWhitespaceChar (const String& line) throw()
{
const int len = line.length();
String::CharPointerType t (line.getCharPointer());
int i = 0;
for (int i = 0; i < len; ++i)
if (! CharacterFunctions::isWhitespace (line [i]))
while (! t.isEmpty())
{
if (! t.isWhitespace())
return i;
++t;
++i;
}
return 0;
}
}
@@ -1119,13 +1126,18 @@ void CodeEditorComponent::setTabSize (const int numSpaces, const bool insertSpac
int CodeEditorComponent::indexToColumn (int lineNum, int index) const throw()
{
const String line (document.getLine (lineNum));
jassert (index <= line.length());
String::CharPointerType t (document.getLine (lineNum).getCharPointer());
int col = 0;
for (int i = 0; i < index; ++i)
{
if (line[i] != '\t')
if (t.isEmpty())
{
jassertfalse;
break;
}
if (t.getAndAdvance() != '\t')
++col;
else
col += getTabSize() - (col % getTabSize());
@@ -1136,19 +1148,21 @@ int CodeEditorComponent::indexToColumn (int lineNum, int index) const throw()
int CodeEditorComponent::columnToIndex (int lineNum, int column) const throw()
{
const String line (document.getLine (lineNum));
const int lineLength = line.length();
String::CharPointerType t (document.getLine (lineNum).getCharPointer());
int i, col = 0;
for (i = 0; i < lineLength; ++i)
int i = 0, col = 0;
while (! t.isEmpty())
{
if (line[i] != '\t')
if (t.getAndAdvance() != '\t')
++col;
else
col += getTabSize() - (col % getTabSize());
if (col > column)
break;
++i;
}
return i;


+ 34
- 32
src/gui/components/controls/juce_TextEditor.cpp View File

@@ -33,6 +33,7 @@ BEGIN_JUCE_NAMESPACE
#include "../../../utilities/juce_SystemClipboard.h"
#include "../../../core/juce_Time.h"
#include "../../../text/juce_LocalisedStrings.h"
#include "../../../io/streams/juce_MemoryOutputStream.h"
#include "../lookandfeel/juce_LookAndFeel.h"
@@ -207,14 +208,13 @@ public:
return section2;
}
void appendAllText (String::Concatenator& concatenator) const
void appendAllText (MemoryOutputStream& mo) const
{
for (int i = 0; i < atoms.size(); ++i)
concatenator.append (getAtom(i)->atomText);
mo << getAtom(i)->atomText;
}
void appendSubstring (String::Concatenator& concatenator,
const Range<int>& range) const
void appendSubstring (MemoryOutputStream& mo, const Range<int>& range) const
{
int index = 0;
for (int i = 0; i < atoms.size(); ++i)
@@ -230,7 +230,7 @@ public:
const Range<int> r ((range - index).getIntersectionWith (Range<int> (0, (int) atom->numChars)));
if (! r.isEmpty())
concatenator.append (atom->atomText.substring (r.getStart(), r.getEnd()));
mo << atom->atomText.substring (r.getStart(), r.getEnd());
}
index = nextIndex;
@@ -1834,7 +1834,8 @@ void TextEditor::mouseDoubleClick (const MouseEvent& e)
while (tokenEnd < totalLength)
{
// (note the slight bodge here - it's because iswalnum only checks for alphabetic chars in the current locale)
if (CharacterFunctions::isLetterOrDigit (t [tokenEnd]) || t [tokenEnd] > 128)
const juce_wchar c = t [tokenEnd];
if (CharacterFunctions::isLetterOrDigit (c) || c > 128)
++tokenEnd;
else
break;
@@ -1845,7 +1846,8 @@ void TextEditor::mouseDoubleClick (const MouseEvent& e)
while (tokenStart > 0)
{
// (note the slight bodge here - it's because iswalnum only checks for alphabetic chars in the current locale)
if (CharacterFunctions::isLetterOrDigit (t [tokenStart - 1]) || t [tokenStart - 1] > 128)
const juce_wchar c = t [tokenStart - 1];
if (CharacterFunctions::isLetterOrDigit (c) || c > 128)
--tokenStart;
else
break;
@@ -1855,7 +1857,8 @@ void TextEditor::mouseDoubleClick (const MouseEvent& e)
{
while (tokenEnd < totalLength)
{
if (t [tokenEnd] != '\r' && t [tokenEnd] != '\n')
const juce_wchar c = t [tokenEnd];
if (c != '\r' && c != '\n')
++tokenEnd;
else
break;
@@ -1863,7 +1866,8 @@ void TextEditor::mouseDoubleClick (const MouseEvent& e)
while (tokenStart > 0)
{
if (t [tokenStart - 1] != '\r' && t [tokenStart - 1] != '\n')
const juce_wchar c = t [tokenStart - 1];
if (c != '\r' && c != '\n')
--tokenStart;
else
break;
@@ -2426,44 +2430,42 @@ void TextEditor::remove (const Range<int>& range,
//==============================================================================
const String TextEditor::getText() const
{
String t;
t.preallocateStorage (getTotalNumChars());
String::Concatenator concatenator (t);
MemoryOutputStream mo;
mo.preallocate (getTotalNumChars());
for (int i = 0; i < sections.size(); ++i)
sections.getUnchecked (i)->appendAllText (concatenator);
sections.getUnchecked (i)->appendAllText (mo);
return t;
return mo.toString();
}
const String TextEditor::getTextInRange (const Range<int>& range) const
{
String t;
if (range.isEmpty())
return String::empty;
if (! range.isEmpty())
{
t.preallocateStorage (jmin (getTotalNumChars(), range.getLength()));
String::Concatenator concatenator (t);
int index = 0;
MemoryOutputStream mo;
mo.preallocate (jmin (getTotalNumChars(), range.getLength()));
for (int i = 0; i < sections.size(); ++i)
{
const UniformTextSection* const s = sections.getUnchecked (i);
const int nextIndex = index + s->getTotalLength();
int index = 0;
if (range.getStart() < nextIndex)
{
if (range.getEnd() <= index)
break;
for (int i = 0; i < sections.size(); ++i)
{
const UniformTextSection* const s = sections.getUnchecked (i);
const int nextIndex = index + s->getTotalLength();
s->appendSubstring (concatenator, range - index);
}
if (range.getStart() < nextIndex)
{
if (range.getEnd() <= index)
break;
index = nextIndex;
s->appendSubstring (mo, range - index);
}
index = nextIndex;
}
return t;
return mo.toString();
}
const String TextEditor::getHighlightedText() const


+ 1
- 1
src/gui/components/juce_Component.cpp View File

@@ -224,7 +224,7 @@ public:
static const Identifier getColourPropertyId (const int colourId)
{
String s;
s.preallocateStorage (18);
s.preallocateBytes (32);
s << "jcclr_" << String::toHexString (colourId);
return s;
}


+ 1
- 1
src/gui/components/windows/juce_ComponentPeer.cpp View File

@@ -497,7 +497,7 @@ public:
void messageCallback()
{
if (target != 0)
if (target.get() != 0)
dropTarget->filesDropped (files, position.getX(), position.getY());
}


+ 14
- 5
src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp View File

@@ -2079,6 +2079,18 @@ public:
}
}
void drawGlyph (const Font& f, int glyphNumber, const AffineTransform& transform)
{
const ScopedPointer<EdgeTable> et (f.getTypeface()->getEdgeTableForGlyph (glyphNumber, getTransformWith (transform)));
if (et != 0)
{
SoftwareRendererClasses::ClipRegion_EdgeTable* edgeTableClip = new SoftwareRendererClasses::ClipRegion_EdgeTable (*et);
SoftwareRendererClasses::ClipRegionBase::Ptr shapeToFill (edgeTableClip);
fillShape (shapeToFill, false);
}
}
void fillShape (SoftwareRendererClasses::ClipRegionBase::Ptr shapeToFill, const bool replaceContents)
{
jassert (clip != 0);
@@ -2523,11 +2535,8 @@ void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineT
else
{
const float fontHeight = f.getHeight();
const ScopedPointer<EdgeTable> et (f.getTypeface()->getEdgeTableForGlyph (glyphNumber,
AffineTransform::scale (fontHeight * f.getHorizontalScale(), fontHeight)
.followedBy (transform)));
if (et != 0)
currentState->fillEdgeTable (*et, 0.0f, 0);
currentState->drawGlyph (f, glyphNumber, AffineTransform::scale (fontHeight * f.getHorizontalScale(), fontHeight)
.followedBy (transform));
}
}


+ 1
- 1
src/gui/graphics/geometry/juce_Rectangle.h View File

@@ -703,7 +703,7 @@ public:
const String toString() const
{
String s;
s.preallocateStorage (16);
s.preallocateBytes (32);
s << x << ' ' << y << ' ' << w << ' ' << h;
return s;
}


+ 19
- 11
src/io/files/juce_File.cpp View File

@@ -868,19 +868,24 @@ const String File::getRelativePathFrom (const File& dir) const
const int len = jmin (thisPath.length(), dirPath.length());
int commonBitLength = 0;
for (int i = 0; i < len; ++i)
{
#if NAMES_ARE_CASE_SENSITIVE
if (thisPath[i] != dirPath[i])
#else
if (CharacterFunctions::toLowerCase (thisPath[i])
!= CharacterFunctions::toLowerCase (dirPath[i]))
#endif
String::CharPointerType thisPathIter (thisPath.getCharPointer());
String::CharPointerType dirPathIter (dirPath.getCharPointer());
for (int i = 0; i < len; ++i)
{
break;
}
const juce_wchar c1 = thisPathIter.getAndAdvance();
const juce_wchar c2 = dirPathIter.getAndAdvance();
++commonBitLength;
#if NAMES_ARE_CASE_SENSITIVE
if (c1 != c2)
#else
if (c1 != c2 && CharacterFunctions::toLowerCase (c1) != CharacterFunctions::toLowerCase (c2))
#endif
break;
++commonBitLength;
}
}
while (commonBitLength > 0 && thisPath [commonBitLength - 1] != File::separator)
@@ -1002,6 +1007,9 @@ public:
expect (tempFile.hasFileExtension (".txt"));
expect (tempFile.hasFileExtension ("txt"));
expect (tempFile.withFileExtension ("xyz").hasFileExtension (".xyz"));
expect (tempFile.withFileExtension ("xyz").hasFileExtension ("abc;xyz;foo"));
expect (tempFile.withFileExtension ("xyz").hasFileExtension ("xyz;foo"));
expect (! tempFile.withFileExtension ("h").hasFileExtension ("bar;foo;xx"));
expect (tempFile.getSiblingFile ("foo").isAChildOf (temp));
expect (tempFile.hasWriteAccess());
@@ -1013,7 +1021,7 @@ public:
expect (tempFile.exists());
expect (tempFile.getSize() == 10);
expect (std::abs ((int) (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000);
expect (tempFile.loadFileAsString() == "0123456789");
expectEquals (tempFile.loadFileAsString(), String ("0123456789"));
expect (! demoFolder.containsSubDirectories());
expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() + File::separatorString + tempFile.getFileName());


+ 0
- 1
src/io/network/juce_MACAddress.cpp View File

@@ -56,7 +56,6 @@ MACAddress::MACAddress (const uint8 bytes[6])
const String MACAddress::toString() const
{
String s;
s.preallocateStorage (18);
for (int i = 0; i < numElementsInArray (asBytes); ++i)
{


+ 1
- 1
src/io/streams/juce_MemoryOutputStream.cpp View File

@@ -131,7 +131,7 @@ int MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumB
const String MemoryOutputStream::toUTF8() const
{
return String::fromUTF8 (static_cast <const char*> (getData()), getDataSize());
return String::fromUTF8 (static_cast <const char*> (getData()), (int) getDataSize());
}
const String MemoryOutputStream::toString() const


+ 3
- 3
src/memory/juce_MemoryBlock.cpp View File

@@ -284,7 +284,7 @@ void MemoryBlock::loadFromHexString (const String& hex)
{
ensureSize (hex.length() >> 1);
char* dest = data;
int i = 0;
String::CharPointerType t (hex.getCharPointer());
for (;;)
{
@@ -296,7 +296,7 @@ void MemoryBlock::loadFromHexString (const String& hex)
for (;;)
{
const juce_wchar c = hex [i++];
const juce_wchar c = t.getAndAdvance();
if (c >= '0' && c <= '9')
{
@@ -334,7 +334,7 @@ const String MemoryBlock::toBase64Encoding() const
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
const int initialLen = destString.length();
destString.preallocateStorage (initialLen + 2 + numChars);
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (initialLen + 2 + numChars));
String::CharPointerType d (destString.getCharPointer());
d += initialLen;


+ 1
- 9
src/native/linux/juce_linux_Clipboard.cpp View File

@@ -146,15 +146,7 @@ void juce_handleSelectionRequest (XSelectionRequestEvent &evt)
if (evt.selection == XA_PRIMARY || evt.selection == ClipboardHelpers::atom_CLIPBOARD)
{
if (evt.target == XA_STRING)
{
// format data according to system locale
numDataItems = ClipboardHelpers::localClipboardContent.getNumBytesAsCString() + 1;
data.calloc (numDataItems + 1);
ClipboardHelpers::localClipboardContent.copyToCString (data, numDataItems);
propertyFormat = 8; // bits/item
}
else if (evt.target == ClipboardHelpers::atom_UTF8_STRING)
if (evt.target == XA_STRING || evt.target == ClipboardHelpers::atom_UTF8_STRING)
{
// translate to utf8
numDataItems = ClipboardHelpers::localClipboardContent.getNumBytesAsUTF8() + 1;


+ 2
- 2
src/native/linux/juce_linux_Messaging.cpp View File

@@ -268,7 +268,7 @@ namespace LinuxErrorHandling
char requestStr[64] = { 0 };
XGetErrorText (display, event->error_code, errorStr, 64);
XGetErrorDatabaseText (display, "XRequest", String (event->request_code).toCString(), "Unknown", requestStr, 64);
XGetErrorDatabaseText (display, "XRequest", String (event->request_code).toUTF8(), "Unknown", requestStr, 64);
DBG ("ERROR: X returned " + String (errorStr) + " for operation " + String (requestStr));
#endif
@@ -345,7 +345,7 @@ void MessageManager::doPlatformSpecificInitialisation()
if (displayName.isEmpty())
displayName = ":0.0";
display = XOpenDisplay (displayName.toCString());
display = XOpenDisplay (displayName.toUTF8());
if (display != 0) // This is not fatal! we can run headless.
{


+ 1
- 1
src/native/linux/juce_linux_Midi.cpp View File

@@ -128,7 +128,7 @@ namespace
: SND_SEQ_OPEN_OUTPUT, 0) == 0)
{
snd_seq_set_client_name (seqHandle,
(deviceNameToOpen + (forInput ? " Input" : " Output")).toCString());
(deviceNameToOpen + (forInput ? " Input" : " Output")).toUTF8());
const int portId
= snd_seq_create_simple_port (seqHandle,


+ 1
- 1
src/native/linux/juce_linux_Threads.cpp View File

@@ -125,7 +125,7 @@ void PlatformUtilities::freeDynamicLibrary (void* handle)
void* PlatformUtilities::getProcedureEntryPoint (void* libraryHandle, const String& procedureName)
{
return dlsym (libraryHandle, procedureName.toCString());
return dlsym (libraryHandle, procedureName.toUTF8());
}
#endif


+ 9
- 27
src/native/mac/juce_mac_Strings.mm View File

@@ -39,44 +39,26 @@ namespace
{
return [NSString stringWithUTF8String: s.toUTF8()];
}
//==============================================================================
const String convertUTF16ToString (const UniChar* utf16)
{
String s;
while (*utf16 != 0)
s += (juce_wchar) *utf16++;
return s;
}
}
const String PlatformUtilities::cfStringToJuceString (CFStringRef cfString)
{
String result;
if (cfString == 0)
return String::empty;
if (cfString != 0)
{
CFRange range = { 0, CFStringGetLength (cfString) };
HeapBlock <UniChar> u (range.length + 1);
CFStringGetCharacters (cfString, range, u);
u[range.length] = 0;
result = convertUTF16ToString (u);
}
CFRange range = { 0, CFStringGetLength (cfString) };
HeapBlock <UniChar> u (range.length + 1);
CFStringGetCharacters (cfString, range, u);
u[range.length] = 0;
return result;
return String (CharPointer_UTF16 ((const CharPointer_UTF16::CharType*) u.getData()));
}
CFStringRef PlatformUtilities::juceStringToCFString (const String& s)
{
const int len = s.length();
HeapBlock <UniChar> temp (len + 2);
for (int i = 0; i <= len; ++i)
temp[i] = s[i];
CharPointer_UTF16 utf16 (s.toUTF16());
return CFStringCreateWithCharacters (kCFAllocatorDefault, temp, len);
return CFStringCreateWithCharacters (kCFAllocatorDefault, (const UniChar*) utf16.getAddress(), utf16.length());
}
const String PlatformUtilities::convertToPrecomposedUnicode (const String& s)


+ 2
- 0
src/native/windows/juce_win32_Files.cpp View File

@@ -58,6 +58,8 @@ namespace WindowsFileHelpers
const String getDriveFromPath (String path)
{
// (mess with the string to make sure it's not sharing its internal storage)
path = (path + " ").dropLastCharacters(1);
WCHAR* p = const_cast <WCHAR*> (path.toUTF16().getAddress());
if (PathStripToRoot (p))


+ 4
- 4
src/native/windows/juce_win32_Network.cpp View File

@@ -459,8 +459,8 @@ bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAdd
{
MapiMessage message;
zerostruct (message);
message.lpszSubject = (LPSTR) emailSubject.toCString();
message.lpszNoteText = (LPSTR) bodyText.toCString();
message.lpszSubject = (LPSTR) emailSubject.toUTF8().getAddress();
message.lpszNoteText = (LPSTR) bodyText.toUTF8().getAddress();
MapiRecipDesc recip;
zerostruct (recip);
@@ -468,7 +468,7 @@ bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAdd
String targetEmailAddress_ (targetEmailAddress);
if (targetEmailAddress_.isEmpty())
targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
recip.lpszName = (LPSTR) targetEmailAddress_.toCString();
recip.lpszName = (LPSTR) targetEmailAddress_.toUTF8().getAddress();
message.nRecipCount = 1;
message.lpRecips = &recip;
@@ -481,7 +481,7 @@ bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAdd
for (int i = 0; i < filesToAttach.size(); ++i)
{
files[i].nPosition = (ULONG) -1;
files[i].lpszPathName = (LPSTR) filesToAttach[i].toCString();
files[i].lpszPathName = (LPSTR) filesToAttach[i].toUTF8().getAddress();
}
ok = (mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS);


+ 5
- 4
src/native/windows/juce_win32_Threads.cpp View File

@@ -166,7 +166,7 @@ void Thread::setCurrentThreadName (const String& name)
} info;
info.dwType = 0x1000;
info.szName = name.toCString();
info.szName = name.toUTF8();
info.dwThreadID = GetCurrentThreadId();
info.dwFlags = 0;
@@ -337,7 +337,7 @@ void PlatformUtilities::freeDynamicLibrary (void* h)
void* PlatformUtilities::getProcedureEntryPoint (void* h, const String& name)
{
return (h != 0) ? (void*) GetProcAddress ((HMODULE) h, name.toCString()) : 0; // (void* cast is required for mingw)
return (h != 0) ? (void*) GetProcAddress ((HMODULE) h, name.toUTF8()) : 0; // (void* cast is required for mingw)
}
@@ -345,10 +345,11 @@ void* PlatformUtilities::getProcedureEntryPoint (void* h, const String& name)
class InterProcessLock::Pimpl
{
public:
Pimpl (const String& name, const int timeOutMillisecs)
Pimpl (String name, const int timeOutMillisecs)
: handle (0), refCount (1)
{
handle = CreateMutex (0, TRUE, ("Global\\" + name.replaceCharacter ('\\','/')).toUTF16());
name = "Local\\" + name.replaceCharacter ('\\', '/');
handle = CreateMutexW (0, TRUE, name.toUTF16().getAddress());
if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS)
{


+ 40
- 3
src/text/juce_CharPointer_UTF16.h View File

@@ -103,6 +103,17 @@ public:
return *this;
}
/** Moves this pointer back to the previous character in the string. */
CharPointer_UTF16& operator--() throw()
{
const juce_wchar n = *--data;
if (n >= 0xdc00 && n <= 0xdfff)
--data;
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
juce_wchar getAndAdvance() throw()
@@ -126,10 +137,22 @@ public:
/** Moves this pointer forwards by the specified number of characters. */
void operator+= (int numToSkip) throw()
{
jassert (numToSkip >= 0);
if (numToSkip < 0)
{
while (++numToSkip <= 0)
--*this;
}
else
{
while (--numToSkip >= 0)
++*this;
}
}
while (--numToSkip >= 0)
++*this;
/** Moves this pointer backwards by the specified number of characters. */
void operator-= (int numToSkip) throw()
{
operator+= (-numToSkip);
}
/** Returns the character at a given character index from the start of the string. */
@@ -148,6 +171,14 @@ public:
return p;
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF16 operator- (const int numToSkip) const throw()
{
CharPointer_UTF16 p (*this);
p += -numToSkip;
return p;
}
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
void write (juce_wchar charToWrite) throw()
{
@@ -434,6 +465,12 @@ public:
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF16 atomicSwap (const CharPointer_UTF16& newValue)
{
return CharPointer_UTF16 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
}
/** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */
enum
{


+ 48
- 3
src/text/juce_CharPointer_UTF8.h View File

@@ -131,6 +131,25 @@ public:
return *this;
}
/** Moves this pointer back to the previous character in the string. */
CharPointer_UTF8& operator--() throw()
{
const char n = *--data;
if ((n & 0xc0) == 0xc0)
{
int count = 3;
do
{
--data;
}
while ((*data & 0xc0) == 0xc0 && --count >= 0);
}
return *this;
}
/** Returns the character that this pointer is currently pointing to, and then
advances the pointer to point to the next character. */
juce_wchar getAndAdvance() throw()
@@ -179,10 +198,22 @@ public:
/** Moves this pointer forwards by the specified number of characters. */
void operator+= (int numToSkip) throw()
{
jassert (numToSkip >= 0);
if (numToSkip < 0)
{
while (++numToSkip <= 0)
--*this;
}
else
{
while (--numToSkip >= 0)
++*this;
}
}
while (--numToSkip >= 0)
++*this;
/** Moves this pointer backwards by the specified number of characters. */
void operator-= (int numToSkip) throw()
{
operator+= (-numToSkip);
}
/** Returns the character at a given character index from the start of the string. */
@@ -201,6 +232,14 @@ public:
return p;
}
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
CharPointer_UTF8 operator- (int numToSkip) const throw()
{
CharPointer_UTF8 p (*this);
p += -numToSkip;
return p;
}
/** Returns the number of characters in this string. */
size_t length() const throw()
{
@@ -520,6 +559,12 @@ public:
return true;
}
/** Atomically swaps this pointer for a new value, returning the previous value. */
CharPointer_UTF8 atomicSwap (const CharPointer_UTF8& newValue)
{
return CharPointer_UTF8 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
}
/** These values are the byte-order-mark (BOM) values for a UTF-8 stream. */
enum
{


+ 0
- 18
src/text/juce_CharacterFunctions.cpp View File

@@ -132,24 +132,6 @@ int CharacterFunctions::getHexDigitValue (const juce_wchar digit) throw()
return -1;
}
int CharacterFunctions::ftime (char* const dest, const int maxChars, const char* const format, const struct tm* const tm) throw()
{
return (int) strftime (dest, maxChars, format, tm);
}
int CharacterFunctions::ftime (juce_wchar* const dest, const int maxChars, const juce_wchar* const format, const struct tm* const tm) throw()
{
#if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
return (int) wcsftime (dest, maxChars, format, tm);
#else
HeapBlock <char> tempDest;
tempDest.calloc (maxChars + 2);
int result = ftime (tempDest.getData(), maxChars, String (format).toUTF8(), tm);
CharPointer_UTF32 (dest).writeAll (CharPointer_UTF8 (tempDest.getData()));
return result;
#endif
}
#if JUCE_MSVC
#pragma warning (pop)
#endif


+ 18
- 4
src/text/juce_CharacterFunctions.h View File

@@ -266,10 +266,6 @@ public:
return isNeg ? -v : v;
}
//==============================================================================
static int ftime (char* dest, int maxChars, const char* format, const struct tm* tm) throw();
static int ftime (juce_wchar* dest, int maxChars, const juce_wchar* format, const struct tm* tm) throw();
//==============================================================================
template <typename CharPointerType>
static size_t lengthUpTo (CharPointerType text, const size_t maxCharsToCount) throw()
@@ -441,6 +437,24 @@ public:
}
}
template <typename CharPointerType1, typename CharPointerType2>
static int indexOfIgnoreCase (CharPointerType1 haystack, const CharPointerType2& needle) throw()
{
int index = 0;
const int needleLength = (int) needle.length();
for (;;)
{
if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
return index;
if (haystack.getAndAdvance() == 0)
return -1;
++index;
}
}
template <typename Type>
static int indexOfChar (Type text, const juce_wchar charToFind) throw()
{


+ 2
- 2
src/text/juce_Identifier.h View File

@@ -76,11 +76,11 @@ public:
const String toString() const { return name; }
/** Returns this identifier's raw string pointer. */
operator const juce_wchar*() const throw() { return name; }
operator const String::CharPointerType() const throw() { return name; }
private:
//==============================================================================
const juce_wchar* name;
String::CharPointerType name;
static StringPool& getPool();
};


+ 2
- 1
src/text/juce_LocalisedStrings.cpp View File

@@ -59,10 +59,11 @@ namespace
int findCloseQuote (const String& text, int startPos)
{
juce_wchar lastChar = 0;
String::CharPointerType t (text.getCharPointer() + startPos);
for (;;)
{
const juce_wchar c = text [startPos];
const juce_wchar c = t.getAndAdvance();
if (c == 0 || (c == '"' && lastChar != '\\'))
break;


+ 491
- 342
src/text/juce_String.cpp
File diff suppressed because it is too large
View File


+ 113
- 96
src/text/juce_String.h View File

@@ -28,6 +28,10 @@
#include "juce_CharacterFunctions.h"
#ifndef JUCE_STRING_UTF_TYPE
#define JUCE_STRING_UTF_TYPE 8
#endif
#if JUCE_MSVC
#pragma warning (push)
#pragma warning (disable: 4514 4996)
@@ -45,7 +49,6 @@
class OutputStream;
//==============================================================================
/**
The JUCE String class!
@@ -111,12 +114,35 @@ public:
*/
String (const juce_wchar* unicodeText, size_t maxChars);
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
/** Creates a string from a UTF-16 character string */
String (const wchar_t* text);
/** Creates a string from a UTF-16 character string */
String (const wchar_t* text, size_t maxChars);
#endif
//==============================================================================
/** Creates a string from a UTF-8 character string */
String (const CharPointer_UTF8& text);
/** Creates a string from a UTF-8 character string */
String (const CharPointer_UTF8& text, size_t maxChars);
/** Creates a string from a UTF-8 character string */
String (const CharPointer_UTF8& start, const CharPointer_UTF8& end);
//==============================================================================
/** Creates a string from a UTF-16 character string */
String (const CharPointer_UTF16& text);
/** Creates a string from a UTF-16 character string */
String (const CharPointer_UTF16& text, size_t maxChars);
/** Creates a string from a UTF-16 character string */
String (const CharPointer_UTF16& start, const CharPointer_UTF16& end);
//==============================================================================
/** Creates a string from a UTF-32 character string */
String (const CharPointer_UTF32& text);
@@ -126,17 +152,11 @@ public:
/** 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);
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
/** Creates a string from a UTF-16 character string */
String (const wchar_t* text);
/** Creates a string from a UTF-16 character string */
String (const wchar_t* text, size_t maxChars);
#endif
//==============================================================================
/** Creates a string from a single character. */
static const String charToString (juce_wchar character);
@@ -151,8 +171,27 @@ public:
*/
static const String empty;
/** This is the character encoding type used internally to store the string. */
/** This is the character encoding type used internally to store the string.
By setting the value of JUCE_STRING_UTF_TYPE to 8, 16, or 32, you can change the
internal storage format of the String class. UTF-8 uses the least space (if your strings
contain few extended characters), but call operator[] involves iterating the string to find
the required index. UTF-32 provides instant random access to its characters, but uses 4 bytes
per character to store them. UTF-16 uses more space than UTF-8 and is also slow to index,
but is the native wchar_t format used in Windows.
It doesn't matter too much which format you pick, because the toUTF8(), toUTF16() and
toUTF32() methods let you access the string's content in any of the other formats.
*/
#if (JUCE_STRING_UTF_TYPE == 32)
typedef CharPointer_UTF32 CharPointerType;
#elif (JUCE_STRING_UTF_TYPE == 16)
typedef CharPointer_UTF16 CharPointerType;
#elif (JUCE_STRING_UTF_TYPE == 8)
typedef CharPointer_UTF8 CharPointerType;
#else
#error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!"
#endif
//==============================================================================
/** Generates a probably-unique 32-bit hashcode from this string. */
@@ -204,13 +243,21 @@ public:
{
if (textToAppend.getAddress() != 0)
{
const size_t numExtraChars = textToAppend.lengthUpTo (maxCharsToTake);
size_t extraBytesNeeded = 0;
size_t numChars = 0;
for (CharPointer t (textToAppend); numChars < maxCharsToTake && ! t.isEmpty();)
{
extraBytesNeeded += CharPointerType::getBytesRequiredFor (t.getAndAdvance());
++numChars;
}
if (numExtraChars > 0)
if (numChars > 0)
{
const int oldLen = length();
preallocateStorage (oldLen + numExtraChars);
CharPointerType (text + oldLen).writeWithCharLimit (textToAppend, (int) (numExtraChars + 1));
const size_t byteOffsetOfNull = getByteOffsetOfEnd();
preallocateBytes (byteOffsetOfNull + extraBytesNeeded);
CharPointerType (addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull)).writeWithCharLimit (textToAppend, (int) (numChars + 1));
}
}
}
@@ -225,13 +272,17 @@ public:
{
if (textToAppend.getAddress() != 0)
{
const size_t numExtraChars = textToAppend.length();
size_t extraBytesNeeded = 0;
for (CharPointer t (textToAppend); ! t.isEmpty();)
extraBytesNeeded += CharPointerType::getBytesRequiredFor (t.getAndAdvance());
if (numExtraChars > 0)
if (extraBytesNeeded > 0)
{
const int oldLen = length();
preallocateStorage (oldLen + numExtraChars);
CharPointerType (text + oldLen).writeAll (textToAppend);
const size_t byteOffsetOfNull = getByteOffsetOfEnd();
preallocateBytes (byteOffsetOfNull + extraBytesNeeded);
CharPointerType (addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull)).writeAll (textToAppend);
}
}
}
@@ -430,18 +481,14 @@ public:
// Substring location methods..
/** Searches for a character inside this string.
Uses a case-sensitive comparison.
@returns the index of the first occurrence of the character in this
string, or -1 if it's not found.
*/
int indexOfChar (juce_wchar characterToLookFor) const throw();
/** Searches for a character inside this string.
Uses a case-sensitive comparison.
@param startIndex the index from which the search should proceed
@param characterToLookFor the character to look for
@returns the index of the first occurrence of the character in this
@@ -466,67 +513,54 @@ public:
bool ignoreCase = false) const throw();
/** Searches for a substring within this string.
Uses a case-sensitive comparison.
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return 0.
*/
int indexOf (const String& text) const throw();
int indexOf (const String& textToLookFor) const throw();
/** Searches for a substring within this string.
Uses a case-sensitive comparison.
@param startIndex the index from which the search should proceed
@param textToLookFor the string to search for
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return -1.
*/
int indexOf (int startIndex,
const String& textToLookFor) const throw();
int indexOf (int startIndex, const String& textToLookFor) const throw();
/** Searches for a substring within this string.
Uses a case-insensitive comparison.
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return 0.
*/
int indexOfIgnoreCase (const String& textToLookFor) const throw();
/** Searches for a substring within this string.
Uses a case-insensitive comparison.
@param startIndex the index from which the search should proceed
@param textToLookFor the string to search for
@returns the index of the first occurrence of this substring, or -1 if it's not found.
If textToLookFor is an empty string, this will always return -1.
*/
int indexOfIgnoreCase (int startIndex,
const String& textToLookFor) const throw();
int indexOfIgnoreCase (int startIndex, const String& textToLookFor) const throw();
/** Searches for a character inside this string (working backwards from the end of the string).
Uses a case-sensitive comparison.
@returns the index of the last occurrence of the character in this
string, or -1 if it's not found.
@returns the index of the last occurrence of the character in this string, or -1 if it's not found.
*/
int lastIndexOfChar (juce_wchar character) const throw();
/** Searches for a substring inside this string (working backwards from the end of the string).
Uses a case-sensitive comparison.
@returns the index of the start of the last occurrence of the
substring within this string, or -1 if it's not found.
@returns the index of the start of the last occurrence of the substring within this string,
or -1 if it's not found. If textToLookFor is an empty string, this will always return -1.
*/
int lastIndexOf (const String& textToLookFor) const throw();
/** Searches for a substring inside this string (working backwards from the end of the string).
Uses a case-insensitive comparison.
@returns the index of the start of the last occurrence of the
substring within this string, or -1 if it's not found.
@returns the index of the start of the last occurrence of the substring within this string, or -1
if it's not found. If textToLookFor is an empty string, this will always return -1.
*/
int lastIndexOfIgnoreCase (const String& textToLookFor) const throw();
@@ -550,8 +584,15 @@ public:
// Substring extraction and manipulation methods..
/** Returns the character at this index in the string.
In a release build, no checks are made to see if the index is within a valid range, so be
careful! In a debug build, the index is checked and an assertion fires if it's out-of-range.
No checks are made to see if the index is within a valid range, so be careful!
Also beware that depending on the encoding format that the string is using internally, this
method may execute in either O(1) or O(n) time, so be careful when using it in your algorithms.
If you're scanning through a string to inspect its characters, you should never use this operator
for random access, it's far more efficient to call getCharPointer() to return a pointer, and
then to use that to iterate the string.
@see getCharPointer
*/
const juce_wchar operator[] (int index) const throw();
@@ -999,15 +1040,6 @@ public:
int size,
int groupSize = 1);
//==============================================================================
/** Returns a unicode version of this string.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can become invalid whenever
any string methods (even some const ones!) are called.
*/
inline operator const juce_wchar*() const throw() { return toUTF32().getAddress(); }
//==============================================================================
/** Returns the character pointer currently being used to store this string.
@@ -1051,7 +1083,7 @@ public:
@see getCharPointer, toUTF8, toUTF16
*/
inline CharPointer_UTF32 toUTF32() const throw() { return text; }
CharPointer_UTF32 toUTF32() const;
//==============================================================================
/** Creates a String from a UTF-8 encoded buffer.
@@ -1100,35 +1132,22 @@ public:
*/
int copyToUTF16 (CharPointer_UTF16::CharType* destBuffer, int maxBufferSizeBytes) const throw();
//==============================================================================
/** Returns a version of this string using the default 8-bit multi-byte system encoding.
Because it returns a reference to the string's internal data, the pointer
that is returned must not be stored anywhere, as it can be deleted whenever the
string changes.
@see getNumBytesAsCString, copyToCString, toUTF8
*/
const char* toCString() const;
/** Copies the string to a buffer as UTF-16 characters.
/** Returns the number of bytes required to represent this string as C-string.
The number returned does NOT include the trailing zero.
Note that you can also get this value by using CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
*/
int getNumBytesAsCString() const throw();
Returns the number of bytes copied to the buffer, including the terminating null
character.
/** Copies the string to a buffer.
To find out how many bytes you need to store this string as UTF-32, you can call
CharPointer_UTF32::getBytesRequiredFor (myString.getCharPointer())
@param destBuffer the place to copy it to; if this is a null pointer,
the method just returns the number of bytes required
(including the terminating null character).
@param maxBufferSizeBytes the size of the destination buffer, in bytes. If the
string won't fit, it'll put in as many as it can while
still allowing for a terminating null char at the end, and
will return the number of bytes that were actually used.
@param destBuffer the place to copy it to; if this is a null pointer, the method just
returns the number of bytes required (including the terminating null character).
@param maxBufferSizeBytes the size of the destination buffer, in bytes. If the string won't fit, it'll
put in as many as it can while still allowing for a terminating null char at the
end, and will return the number of bytes that were actually used.
@see CharPointer_UTF32::writeWithDestByteLimit
*/
int copyToCString (char* destBuffer, int maxBufferSizeBytes) const throw();
int copyToUTF32 (CharPointer_UTF32::CharType* destBuffer, int maxBufferSizeBytes) const throw();
//==============================================================================
/** Increases the string's internally allocated storage.
@@ -1141,11 +1160,11 @@ public:
beforehand, so that these methods won't have to keep resizing the string
to append the extra characters.
@param numCharsNeeded the number of characters to allocate storage for. If this
@param numBytesNeeded the number of bytes to allocate storage for. If this
value is less than the currently allocated size, it will
have no effect.
*/
void preallocateStorage (size_t numCharsNeeded);
void preallocateBytes (size_t numBytesNeeded);
/** Swaps the contents of this string with another one.
This is a very fast operation, as no allocation or copying needs to be done.
@@ -1182,20 +1201,18 @@ private:
CharPointerType text;
//==============================================================================
struct Preallocation
struct PreallocationBytes
{
explicit Preallocation (size_t);
size_t numChars;
explicit PreallocationBytes (size_t);
size_t numBytes;
};
// This constructor preallocates a certain amount of memory
explicit String (const Preallocation&);
String (const String& stringToCopy, size_t charsToAllocate);
void appendFixedLength (const juce_wchar* text, int numExtraChars);
explicit String (const PreallocationBytes&);
JUCE_DEPRECATED (String (const String& stringToCopy, size_t charsToAllocate));
void enlarge (size_t newTotalNumChars);
void* createSpaceAtEndOfBuffer (size_t numExtraBytes) const;
void appendFixedLength (const char* text, int numExtraChars);
size_t getByteOffsetOfEnd() const throw();
// This private cast operator should prevent strings being accidentally cast
// to bools (this is possible because the compiler can add an implicit cast


+ 5
- 5
src/text/juce_StringArray.cpp View File

@@ -328,14 +328,14 @@ const String StringArray::joinIntoString (const String& separator, int start, in
if (start == last - 1)
return strings.getReference (start);
const int separatorLen = separator.length();
int charsNeeded = separatorLen * (last - start - 1);
const size_t separatorBytes = separator.getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
size_t bytesNeeded = separatorBytes * (last - start - 1);
for (int i = start; i < last; ++i)
charsNeeded += strings.getReference(i).length();
bytesNeeded += strings.getReference(i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
String result;
result.preallocateStorage (charsNeeded);
result.preallocateBytes (bytesNeeded);
String::CharPointerType dest (result.getCharPointer());
@@ -346,7 +346,7 @@ const String StringArray::joinIntoString (const String& separator, int start, in
if (! s.isEmpty())
dest.writeAll (s.getCharPointer());
if (++start < last && separatorLen > 0)
if (++start < last && separatorBytes > 0)
dest.writeAll (separator.getCharPointer());
}


+ 1
- 1
src/text/juce_StringPool.cpp View File

@@ -110,7 +110,7 @@ int StringPool::size() const throw()
return strings.size();
}
const juce_wchar* StringPool::operator[] (const int index) const throw()
const String::CharPointerType StringPool::operator[] (const int index) const throw()
{
return strings [index].getCharPointer();
}


+ 1
- 1
src/text/juce_StringPool.h View File

@@ -81,7 +81,7 @@ public:
int size() const throw();
/** Returns one of the strings in the pool, by index. */
const juce_wchar* operator[] (int index) const throw();
const String::CharPointerType operator[] (int index) const throw();
private:
Array <String> strings;


+ 10
- 8
src/text/juce_XmlDocument.cpp View File

@@ -209,7 +209,7 @@ void XmlDocument::skipHeader()
return;
#if JUCE_DEBUG
const String header ((input + headerStart).getAddress(), headerEnd - headerStart);
const String header (input + headerStart, headerEnd - headerStart);
const String encoding (header.fromFirstOccurrenceOf ("encoding", false, true)
.fromFirstOccurrenceOf ("=", false, false)
.fromFirstOccurrenceOf ("\"", false, false)
@@ -252,7 +252,7 @@ void XmlDocument::skipHeader()
--n;
}
dtdText = String (docType.getAddress(), (int) (input.getAddress() - (docType.getAddress() + 1))).trim();
dtdText = String (docType, (int) (input.getAddress() - (docType.getAddress() + 1))).trim();
}
void XmlDocument::skipNextWhiteSpace()
@@ -383,7 +383,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
}
}
node = new XmlElement (String (input.getAddress(), tagLen));
node = new XmlElement (String (input, tagLen));
input += tagLen;
LinkedListPointer<XmlElement::XmlAttributeNode>::Appender attributeAppender (node->attributes);
@@ -433,7 +433,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
if (nextChar == '"' || nextChar == '\'')
{
XmlElement::XmlAttributeNode* const newAtt
= new XmlElement::XmlAttributeNode (String (attNameStart.getAddress(), attNameLen),
= new XmlElement::XmlAttributeNode (String (attNameStart, attNameLen),
String::empty);
readQuotedString (newAtt->value);
@@ -517,7 +517,7 @@ void XmlDocument::readChildElements (XmlElement* parent)
++len;
}
childAppender.append (XmlElement::createTextElement (String (inputStart.getAddress(), len)));
childAppender.append (XmlElement::createTextElement (String (inputStart, len)));
}
else
{
@@ -713,7 +713,7 @@ void XmlDocument::readEntity (String& result)
{
input += closingSemiColon + 1;
result += expandExternalEntity (String (entityNameStart.getAddress(), closingSemiColon));
result += expandExternalEntity (String (entityNameStart, closingSemiColon));
}
}
}
@@ -728,10 +728,12 @@ const String XmlDocument::expandEntity (const String& ent)
if (ent[0] == '#')
{
if (ent[1] == 'x' || ent[1] == 'X')
const juce_wchar char1 = ent[1];
if (char1 == 'x' || char1 == 'X')
return String::charToString (static_cast <juce_wchar> (ent.substring (2).getHexValue32()));
if (ent[1] >= '0' && ent[1] <= '9')
if (char1 >= '0' && char1 <= '9')
return String::charToString (static_cast <juce_wchar> (ent.substring (1).getIntValue()));
setLastError ("illegal escape sequence", false);


Loading…
Cancel
Save