From e235912ae5600f03e7eb9d98e7337b699a991070 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Thu, 27 Jan 2011 20:34:05 +0000 Subject: [PATCH] Major overhaul of the String class, to rely more heavily on the CharPointer_UTF classes. On win32, the juce_wchar type is now a typedef for a 32-bit int, rather than the 16-bit wchar_t. The String class now has toUTF8(), toUTF16() and toUTF32() methods to retrieve the string in different formats. --- .../Source/MainHostWindow.cpp | 4 +- extras/juce demo/Source/MainDemoWindow.cpp | 28 +- extras/the jucer/build/vc8/jucer.vcproj | 5 +- extras/the jucer/src/jucer_Main.cpp | 6 +- .../model/components/jucer_ButtonHandler.h | 2 +- .../model/components/jucer_ComboBoxHandler.h | 2 +- .../components/jucer_ComponentTypeHandler.cpp | 2 +- .../components/jucer_GroupComponentHandler.h | 2 +- .../components/jucer_HyperlinkButtonHandler.h | 2 +- .../components/jucer_ImageButtonHandler.h | 2 +- .../components/jucer_JucerComponentHandler.h | 2 +- .../src/model/components/jucer_LabelHandler.h | 4 +- .../model/components/jucer_SliderHandler.h | 4 +- .../components/jucer_TabbedComponentHandler.h | 34 +- .../components/jucer_TextButtonHandler.h | 2 +- .../model/components/jucer_TreeViewHandler.h | 2 +- .../model/components/jucer_ViewportHandler.h | 4 +- .../model/documents/jucer_ButtonDocument.cpp | 8 +- .../src/model/jucer_BinaryResources.cpp | 14 +- .../src/model/jucer_ComponentLayout.cpp | 15 +- .../src/model/jucer_ComponentLayout.h | 2 +- .../src/model/jucer_GeneratedCode.cpp | 50 +- .../src/model/jucer_JucerDocument.cpp | 46 +- .../the jucer/src/model/jucer_JucerDocument.h | 2 +- .../the jucer/src/model/jucer_ObjectTypes.cpp | 24 +- .../the jucer/src/model/jucer_ObjectTypes.h | 4 +- .../src/model/jucer_PaintRoutine.cpp | 10 +- .../the jucer/src/model/jucer_PaintRoutine.h | 4 +- .../paintelements/jucer_PaintElementEllipse.h | 2 +- .../paintelements/jucer_PaintElementGroup.h | 2 +- .../paintelements/jucer_PaintElementImage.h | 4 +- .../paintelements/jucer_PaintElementPath.cpp | 52 +- .../paintelements/jucer_PaintElementPath.h | 2 +- .../jucer_PaintElementRectangle.h | 8 +- .../jucer_PaintElementRoundedRectangle.h | 2 +- .../paintelements/jucer_PaintElementText.h | 56 +- .../properties/jucer_JustificationProperty.h | 24 +- .../properties/jucer_PositionPropertyBase.h | 22 +- extras/the jucer/src/ui/jucer_CommandIDs.h | 6 +- .../src/ui/jucer_ComponentLayoutEditor.cpp | 4 +- .../ui/jucer_ComponentOverlayComponent.cpp | 2 +- .../src/ui/jucer_JucerDocumentHolder.cpp | 56 +- extras/the jucer/src/ui/jucer_MainWindow.cpp | 40 +- .../src/ui/jucer_PaintRoutinePanel.cpp | 6 +- extras/the jucer/src/ui/jucer_PrefsPanel.cpp | 6 +- .../src/ui/jucer_ResourceEditorPanel.cpp | 18 +- .../src/utility/jucer_UtilityFunctions.cpp | 120 +- .../src/utility/jucer_UtilityFunctions.h | 4 +- juce_amalgamated.cpp | 1017 +++++----- juce_amalgamated.h | 1665 ++++++++++------- .../juce_OggVorbisAudioFormat.cpp | 2 +- .../plugins/formats/juce_VSTPluginFormat.cpp | 7 +- src/core/juce_StandardHeader.h | 2 +- .../juce_CPlusPlusCodeTokeniser.cpp | 2 +- src/io/network/juce_URL.cpp | 4 +- src/native/linux/juce_linux_Windowing.cpp | 2 +- src/native/mac/juce_mac_Files.mm | 2 +- src/native/mac/juce_mac_Strings.mm | 23 +- .../juce_win32_DynamicLibraryLoader.cpp | 4 +- src/native/windows/juce_win32_FileChooser.cpp | 21 +- src/native/windows/juce_win32_Files.cpp | 70 +- src/native/windows/juce_win32_Fonts.cpp | 4 +- src/native/windows/juce_win32_Messaging.cpp | 4 +- src/native/windows/juce_win32_Misc.cpp | 9 +- src/native/windows/juce_win32_Network.cpp | 4 +- .../windows/juce_win32_PlatformUtils.cpp | 18 +- src/native/windows/juce_win32_SystemStats.cpp | 2 +- src/native/windows/juce_win32_Threads.cpp | 4 +- .../juce_win32_WebBrowserComponent.cpp | 4 +- src/native/windows/juce_win32_Windowing.cpp | 34 +- src/text/juce_CharPointer_UTF16.h | 145 +- src/text/juce_CharPointer_UTF32.h | 134 +- src/text/juce_CharPointer_UTF8.h | 133 +- src/text/juce_CharacterFunctions.cpp | 20 +- src/text/juce_CharacterFunctions.h | 54 +- src/text/juce_String.cpp | 762 ++++---- src/text/juce_String.h | 196 +- src/text/juce_StringArray.cpp | 17 +- src/text/juce_XmlDocument.cpp | 4 +- 79 files changed, 2914 insertions(+), 2177 deletions(-) diff --git a/extras/audio plugin host/Source/MainHostWindow.cpp b/extras/audio plugin host/Source/MainHostWindow.cpp index dc5988809b..3130b572b7 100644 --- a/extras/audio plugin host/Source/MainHostWindow.cpp +++ b/extras/audio plugin host/Source/MainHostWindow.cpp @@ -179,9 +179,9 @@ void MainHostWindow::changeListenerCallback (ChangeBroadcaster*) const StringArray MainHostWindow::getMenuBarNames() { - const tchar* const names[] = { T("File"), T("Plugins"), T("Options"), 0 }; + const char* const names[] = { "File", "Plugins", "Options", 0 }; - return StringArray ((const tchar**) names); + return StringArray (names); } const PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const String& /*menuName*/) diff --git a/extras/juce demo/Source/MainDemoWindow.cpp b/extras/juce demo/Source/MainDemoWindow.cpp index ff24f1bb83..a8208402a8 100644 --- a/extras/juce demo/Source/MainDemoWindow.cpp +++ b/extras/juce demo/Source/MainDemoWindow.cpp @@ -191,54 +191,54 @@ public: case showRendering: result.setInfo ("Graphics Rendering", "Shows the graphics demo", demosCategory, 0); result.setTicked (currentDemoId == showRendering); - result.addDefaultKeypress (T('1'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('1', ModifierKeys::commandModifier); break; case showFontsAndText: result.setInfo ("Fonts and Text", "Shows the fonts & text demo", demosCategory, 0); result.setTicked (currentDemoId == showFontsAndText); - result.addDefaultKeypress (T('2'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('2', ModifierKeys::commandModifier); break; case showWidgets: result.setInfo ("Widgets", "Shows the widgets demo", demosCategory, 0); result.setTicked (currentDemoId == showWidgets); - result.addDefaultKeypress (T('3'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('3', ModifierKeys::commandModifier); break; case showThreading: result.setInfo ("Multithreading", "Shows the threading demo", demosCategory, 0); result.setTicked (currentDemoId == showThreading); - result.addDefaultKeypress (T('4'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('4', ModifierKeys::commandModifier); break; case showTreeView: result.setInfo ("Treeviews", "Shows the treeviews demo", demosCategory, 0); result.setTicked (currentDemoId == showTreeView); - result.addDefaultKeypress (T('5'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('5', ModifierKeys::commandModifier); break; case showTable: result.setInfo ("Table Components", "Shows the table component demo", demosCategory, 0); result.setTicked (currentDemoId == showTable); - result.addDefaultKeypress (T('6'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('6', ModifierKeys::commandModifier); break; case showAudio: result.setInfo ("Audio", "Shows the audio demo", demosCategory, 0); result.setTicked (currentDemoId == showAudio); - result.addDefaultKeypress (T('7'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('7', ModifierKeys::commandModifier); break; case showDragAndDrop: result.setInfo ("Drag-and-drop", "Shows the drag & drop demo", demosCategory, 0); result.setTicked (currentDemoId == showDragAndDrop); - result.addDefaultKeypress (T('8'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('8', ModifierKeys::commandModifier); break; case showOpenGL: result.setInfo ("OpenGL", "Shows the OpenGL demo", demosCategory, 0); - result.addDefaultKeypress (T('9'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('9', ModifierKeys::commandModifier); result.setTicked (currentDemoId == showOpenGL); #if ! JUCE_OPENGL result.setActive (false); @@ -247,7 +247,7 @@ public: case showQuicktime: result.setInfo ("Quicktime", "Shows the Quicktime demo", demosCategory, 0); - result.addDefaultKeypress (T('b'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('b', ModifierKeys::commandModifier); result.setTicked (currentDemoId == showQuicktime); #if ! (JUCE_QUICKTIME && ! JUCE_LINUX) result.setActive (false); @@ -256,7 +256,7 @@ public: case showCamera: result.setInfo ("Camera Capture", "Shows the camera demo", demosCategory, 0); - result.addDefaultKeypress (T('c'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('c', ModifierKeys::commandModifier); result.setTicked (currentDemoId == showCamera); #if ! JUCE_USE_CAMERA result.setActive (false); @@ -265,7 +265,7 @@ public: case showWebBrowser: result.setInfo ("Web Browser", "Shows the web browser demo", demosCategory, 0); - result.addDefaultKeypress (T('i'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('i', ModifierKeys::commandModifier); result.setTicked (currentDemoId == showWebBrowser); #if (! JUCE_WEB_BROWSER) || JUCE_LINUX result.setActive (false); @@ -274,13 +274,13 @@ public: case showCodeEditor: result.setInfo ("Code Editor", "Shows the code editor demo", demosCategory, 0); - result.addDefaultKeypress (T('e'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('e', ModifierKeys::commandModifier); result.setTicked (currentDemoId == showCodeEditor); break; case showInterprocessComms: result.setInfo ("Interprocess Comms", "Shows the interprocess communications demo", demosCategory, 0); - result.addDefaultKeypress (T('0'), ModifierKeys::commandModifier); + result.addDefaultKeypress ('0', ModifierKeys::commandModifier); result.setTicked (currentDemoId == showInterprocessComms); break; diff --git a/extras/the jucer/build/vc8/jucer.vcproj b/extras/the jucer/build/vc8/jucer.vcproj index 07a18ad41a..7673945db2 100644 --- a/extras/the jucer/build/vc8/jucer.vcproj +++ b/extras/the jucer/build/vc8/jucer.vcproj @@ -152,7 +152,6 @@ BufferSecurityCheck="true" RuntimeTypeInfo="true" UsePrecompiledHeader="0" - PrecompiledHeaderThrough="jucer_Headers.h" AssemblerListingLocation=".\Debug/" ObjectFile=".\Debug/" ProgramDataBaseFileName=".\Debug/" @@ -204,7 +203,7 @@ Name="VCAppVerifierTool" /> @@ -243,7 +242,7 @@ > diff --git a/extras/the jucer/src/jucer_Main.cpp b/extras/the jucer/src/jucer_Main.cpp index e12d751d30..91a685ba13 100644 --- a/extras/the jucer/src/jucer_Main.cpp +++ b/extras/the jucer/src/jucer_Main.cpp @@ -56,7 +56,7 @@ public: ImageCache::setCacheTimeout (30 * 1000); if (commandLine.trim().isNotEmpty() - && ! commandLine.trim().startsWithChar (T('-'))) + && ! commandLine.trim().startsWithChar ('-')) anotherInstanceStarted (commandLine); } @@ -84,12 +84,12 @@ public: //============================================================================== const String getApplicationName() { - return T("The Jucer"); + return "The Jucer"; } const String getApplicationVersion() { - return String (JUCER_MAJOR_VERSION) + T(".") + String (JUCER_MINOR_VERSION); + return String (JUCER_MAJOR_VERSION) + "." + String (JUCER_MINOR_VERSION); } bool moreThanOneInstanceAllowed() diff --git a/extras/the jucer/src/model/components/jucer_ButtonHandler.h b/extras/the jucer/src/model/components/jucer_ButtonHandler.h index 7df7d3437c..e8884d4819 100644 --- a/extras/the jucer/src/model/components/jucer_ButtonHandler.h +++ b/extras/the jucer/src/model/components/jucer_ButtonHandler.h @@ -159,7 +159,7 @@ public: callback << "else "; const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component)); - const String userCodeComment (T("UserButtonCode_") + memberVariableName); + const String userCodeComment ("UserButtonCode_" + memberVariableName); callback << "if (buttonThatWasClicked == " << memberVariableName diff --git a/extras/the jucer/src/model/components/jucer_ComboBoxHandler.h b/extras/the jucer/src/model/components/jucer_ComboBoxHandler.h index ae8a0b5b67..9c447be413 100644 --- a/extras/the jucer/src/model/components/jucer_ComboBoxHandler.h +++ b/extras/the jucer/src/model/components/jucer_ComboBoxHandler.h @@ -149,7 +149,7 @@ public: callback << "else "; const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component)); - const String userCodeComment (T("UserComboBoxCode_") + memberVariableName); + const String userCodeComment ("UserComboBoxCode_" + memberVariableName); callback << "if (comboBoxThatHasChanged == " << memberVariableName diff --git a/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp b/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp index cbf8cdd092..85d7496725 100644 --- a/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp +++ b/extras/the jucer/src/model/components/jucer_ComponentTypeHandler.cpp @@ -567,7 +567,7 @@ void ComponentTypeHandler::fillInCreationCode (GeneratedCode& code, Component* c StringArray lines; lines.addLines (params); - params = lines.joinIntoString (T("\n") + String::repeatedString (T(" "), s.length() + 2)); + params = lines.joinIntoString ("\n" + String::repeatedString (" ", s.length() + 2)); s << " (" << params << "));\n"; } diff --git a/extras/the jucer/src/model/components/jucer_GroupComponentHandler.h b/extras/the jucer/src/model/components/jucer_GroupComponentHandler.h index f4adfcfec1..1fb3af5169 100644 --- a/extras/the jucer/src/model/components/jucer_GroupComponentHandler.h +++ b/extras/the jucer/src/model/components/jucer_GroupComponentHandler.h @@ -102,7 +102,7 @@ public: } s << getColourIntialisationCode (component, memberVariableName) - << T('\n'); + << '\n'; code.constructorCode += s; } diff --git a/extras/the jucer/src/model/components/jucer_HyperlinkButtonHandler.h b/extras/the jucer/src/model/components/jucer_HyperlinkButtonHandler.h index b9e17eabcd..54e8ce8afd 100644 --- a/extras/the jucer/src/model/components/jucer_HyperlinkButtonHandler.h +++ b/extras/the jucer/src/model/components/jucer_HyperlinkButtonHandler.h @@ -100,7 +100,7 @@ public: ButtonHandler::fillInCreationCode (code, component, memberVariableName); code.constructorCode << getColourIntialisationCode (component, memberVariableName) - << T('\n'); + << '\n'; } juce_UseDebuggingNewOperator diff --git a/extras/the jucer/src/model/components/jucer_ImageButtonHandler.h b/extras/the jucer/src/model/components/jucer_ImageButtonHandler.h index ff301b8335..80b9b267bd 100644 --- a/extras/the jucer/src/model/components/jucer_ImageButtonHandler.h +++ b/extras/the jucer/src/model/components/jucer_ImageButtonHandler.h @@ -138,7 +138,7 @@ public: String s; s << getColourIntialisationCode (component, memberVariableName) - << T('\n'); + << '\n'; const String indent (String::repeatedString (T(" "), memberVariableName.length() + 13)); diff --git a/extras/the jucer/src/model/components/jucer_JucerComponentHandler.h b/extras/the jucer/src/model/components/jucer_JucerComponentHandler.h index be5752375d..249e3a6c75 100644 --- a/extras/the jucer/src/model/components/jucer_JucerComponentHandler.h +++ b/extras/the jucer/src/model/components/jucer_JucerComponentHandler.h @@ -184,7 +184,7 @@ private: { setJucerComponentFile (document, component, newFile.getRelativePathFrom (document.getFile().getParentDirectory()) - .replaceCharacter (T('\\'), T('/'))); + .replaceCharacter ('\\', '/')); } const File getFile() const diff --git a/extras/the jucer/src/model/components/jucer_LabelHandler.h b/extras/the jucer/src/model/components/jucer_LabelHandler.h index a62adfeef3..6777c3e032 100644 --- a/extras/the jucer/src/model/components/jucer_LabelHandler.h +++ b/extras/the jucer/src/model/components/jucer_LabelHandler.h @@ -143,7 +143,7 @@ public: if (needsCallback (component)) s << memberVariableName << "->addListener (this);\n"; - s << T('\n'); + s << '\n'; code.constructorCode += s; } @@ -163,7 +163,7 @@ public: callback << "else "; const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component)); - const String userCodeComment (T("UserLabelCode_") + memberVariableName); + const String userCodeComment ("UserLabelCode_" + memberVariableName); callback << "if (labelThatHasChanged == " << memberVariableName diff --git a/extras/the jucer/src/model/components/jucer_SliderHandler.h b/extras/the jucer/src/model/components/jucer_SliderHandler.h index cff014e207..bd6431fb84 100644 --- a/extras/the jucer/src/model/components/jucer_SliderHandler.h +++ b/extras/the jucer/src/model/components/jucer_SliderHandler.h @@ -125,7 +125,7 @@ public: if (s->getSkewFactor() != 1.0) r << memberVariableName << "->setSkewFactor (" << s->getSkewFactor() << ");\n"; - r << T('\n'); + r << '\n'; code.constructorCode += r; } @@ -144,7 +144,7 @@ public: callback << "else "; const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component)); - const String userCodeComment (T("UserSliderCode_") + memberVariableName); + const String userCodeComment ("UserSliderCode_" + memberVariableName); callback << "if (sliderThatWasMoved == " << memberVariableName diff --git a/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h b/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h index 9e182d8d9c..d9695ce2ae 100644 --- a/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h +++ b/extras/the jucer/src/model/components/jucer_TabbedComponentHandler.h @@ -150,7 +150,7 @@ public: properties.add (new TabMoveProperty (t, document, i, t->getNumTabs())); - panel.addSection (T("Tab ") + String (i), properties); + panel.addSection ("Tab " + String (i), properties); } } @@ -161,13 +161,13 @@ public: switch (t->getOrientation()) { case TabbedButtonBar::TabsAtTop: - return T("TabbedButtonBar::TabsAtTop"); + return "TabbedButtonBar::TabsAtTop"; case TabbedButtonBar::TabsAtBottom: - return T("TabbedButtonBar::TabsAtBottom"); + return "TabbedButtonBar::TabsAtBottom"; case TabbedButtonBar::TabsAtLeft: - return T("TabbedButtonBar::TabsAtLeft"); + return "TabbedButtonBar::TabsAtLeft"; case TabbedButtonBar::TabsAtRight: - return T("TabbedButtonBar::TabsAtRight"); + return "TabbedButtonBar::TabsAtRight"; default: jassertfalse break; @@ -197,7 +197,7 @@ public: if (doc != 0) { - code.includeFilesCPP.add (getTabJucerFile (t, i).replace (T(".cpp"), T(".h"))); + code.includeFilesCPP.add (getTabJucerFile (t, i).replace (".cpp", ".h")); contentClassName = doc->getClassName(); delete doc; @@ -239,16 +239,16 @@ public: //============================================================================== static void addNewTab (TabbedComponent* tc, const int insertIndex = -1) { - tc->addTab (T("Tab ") + String (tc->getNumTabs()), Colours::lightgrey, + tc->addTab ("Tab " + String (tc->getNumTabs()), Colours::lightgrey, new TabDemoContentComp(), true, insertIndex); } //============================================================================== static XmlElement* getTabState (TabbedComponent* tc, int tabIndex) { - XmlElement* xml = new XmlElement (T("TAB")); - xml->setAttribute (T("name"), tc->getTabNames() [tabIndex]); - setColourXml (*xml, T("colour"), tc->getTabBackgroundColour (tabIndex)); + XmlElement* xml = new XmlElement ("TAB"); + xml->setAttribute ("name", tc->getTabNames() [tabIndex]); + setColourXml (*xml, "colour", tc->getTabBackgroundColour (tabIndex)); TabDemoContentComp* const tdc = dynamic_cast (tc->getTabContentComponent (tabIndex)); jassert (tdc != 0); @@ -266,8 +266,8 @@ public: static void restoreTabState (TabbedComponent* tc, int tabIndex, const XmlElement& xml) { - tc->setTabName (tabIndex, xml.getStringAttribute (T("name"), T("Tab"))); - tc->setTabBackgroundColour (tabIndex, getColourXml (xml, T("colour"), Colours::lightgrey)); + tc->setTabName (tabIndex, xml.getStringAttribute ("name", "Tab")); + tc->setTabBackgroundColour (tabIndex, getColourXml (xml, "colour", Colours::lightgrey)); TabDemoContentComp* const tdc = dynamic_cast (tc->getTabContentComponent (tabIndex)); jassert (tdc != 0); @@ -524,13 +524,13 @@ private: : ComponentChoiceProperty (T("initial tab"), comp, document) { for (int i = 0; i < comp->getNumTabs(); ++i) - choices.add (T("Tab ") + String (i) + T(": \"") + comp->getTabNames() [i] + T("\"")); + choices.add ("Tab " + String (i) + ": \"" + comp->getTabNames() [i] + "\""); } void setIndex (int newIndex) { document.perform (new InitialTabChangeAction (component, *document.getComponentLayout(), newIndex), - T("Change initial tab")); + "Change initial tab"); } int getIndex() const @@ -711,8 +711,8 @@ private: PopupMenu m; for (int i = 0; i < component->getNumTabs(); ++i) - m.addItem (i + 1, T("Delete tab ") + String (i) - + T(": \"") + names[i] + T("\"")); + m.addItem (i + 1, "Delete tab " + String (i) + + ": \"" + names[i] + "\""); const int r = m.showAt (this); @@ -993,7 +993,7 @@ private: { document.perform (new JucerCompFileChangeAction (component, *document.getComponentLayout(), tabIndex, newFile.getRelativePathFrom (document.getFile().getParentDirectory()) - .replaceCharacter (T('\\'), T('/'))), + .replaceCharacter ('\\', '/')), T("Change tab component file")); } diff --git a/extras/the jucer/src/model/components/jucer_TextButtonHandler.h b/extras/the jucer/src/model/components/jucer_TextButtonHandler.h index 3f3a26199f..2e41bec114 100644 --- a/extras/the jucer/src/model/components/jucer_TextButtonHandler.h +++ b/extras/the jucer/src/model/components/jucer_TextButtonHandler.h @@ -88,7 +88,7 @@ public: String s; s << getColourIntialisationCode (component, memberVariableName) - << T('\n'); + << '\n'; code.constructorCode += s; } diff --git a/extras/the jucer/src/model/components/jucer_TreeViewHandler.h b/extras/the jucer/src/model/components/jucer_TreeViewHandler.h index 8f628b91f3..3275a50267 100644 --- a/extras/the jucer/src/model/components/jucer_TreeViewHandler.h +++ b/extras/the jucer/src/model/components/jucer_TreeViewHandler.h @@ -143,7 +143,7 @@ private: : name (name_) { for (int i = 0; i < numItems; ++i) - addSubItem (new DemoTreeViewItem (T("Demo sub-node ") + String (i), numItems - 1)); + addSubItem (new DemoTreeViewItem ("Demo sub-node " + String (i), numItems - 1)); } ~DemoTreeViewItem() diff --git a/extras/the jucer/src/model/components/jucer_ViewportHandler.h b/extras/the jucer/src/model/components/jucer_ViewportHandler.h index d03babc977..8c51c2705e 100644 --- a/extras/the jucer/src/model/components/jucer_ViewportHandler.h +++ b/extras/the jucer/src/model/components/jucer_ViewportHandler.h @@ -154,7 +154,7 @@ public: { code.includeFilesCPP.add (doc->getFile().withFileExtension (T("h")) .getRelativePathFrom (code.document->getFile().getParentDirectory()) - .replaceCharacter (T('\\'), T('/'))); + .replaceCharacter ('\\', '/')); className = doc->getClassName(); delete doc; @@ -518,7 +518,7 @@ private: { document.perform (new JucerCompFileChangeAction (component, *document.getComponentLayout(), newFile.getRelativePathFrom (document.getFile().getParentDirectory()) - .replaceCharacter (T('\\'), T('/')) + .replaceCharacter ('\\', '/') ), T("Change Jucer component file")); } diff --git a/extras/the jucer/src/model/documents/jucer_ButtonDocument.cpp b/extras/the jucer/src/model/documents/jucer_ButtonDocument.cpp index 2762f64be5..934fa5adb5 100644 --- a/extras/the jucer/src/model/documents/jucer_ButtonDocument.cpp +++ b/extras/the jucer/src/model/documents/jucer_ButtonDocument.cpp @@ -63,11 +63,11 @@ ButtonDocument::~ButtonDocument() delete paintRoutines [i]; } -static const tchar* const stateNames[] = +static const char* const stateNames[] = { - T("normal"), T("over"), T("down"), - T("normal on"), T("over on"), T("down on"), - T("common background") + "normal", "over", "down", + "normal on", "over on", "down on", + "common background" }; int stateNameToIndex (const String& name) diff --git a/extras/the jucer/src/model/jucer_BinaryResources.cpp b/extras/the jucer/src/model/jucer_BinaryResources.cpp index a493c413f5..620ce02ae0 100644 --- a/extras/the jucer/src/model/jucer_BinaryResources.cpp +++ b/extras/the jucer/src/model/jucer_BinaryResources.cpp @@ -243,21 +243,21 @@ void BinaryResources::loadFromCpp (const File& cppFileLocation, const String& cp .fromFirstOccurrenceOf (T("{"), false, false)); MemoryOutputStream out; - const tchar* t = (const tchar*) dataString; + const juce_wchar* t = (const juce_wchar*) dataString; int n = 0; while (*t != 0) { - const tchar c = *t++; + const juce_wchar c = *t++; - if (c >= T('0') && c <= T('9')) - n = n * 10 + (c - T('0')); - else if (c == T(',')) + if (c >= '0' && c <= '9') + n = n * 10 + (c - '0'); + else if (c == ',') { out.writeByte ((char) n); n = 0; } - else if (c == T('}')) + else if (c == '}') break; } @@ -299,7 +299,7 @@ void BinaryResources::fillInGeneratedCode (GeneratedCode& code) const << ", \"" << File (resources[i]->originalFilename) .getRelativePathFrom (code.document->getFile()) - .replaceCharacter (T('\\'), T('/')) + .replaceCharacter ('\\', '/') << "\"\n"; String line1; diff --git a/extras/the jucer/src/model/jucer_ComponentLayout.cpp b/extras/the jucer/src/model/jucer_ComponentLayout.cpp index 8c763fa6e7..d254a84b27 100644 --- a/extras/the jucer/src/model/jucer_ComponentLayout.cpp +++ b/extras/the jucer/src/model/jucer_ComponentLayout.cpp @@ -238,7 +238,7 @@ void ComponentLayout::componentToFront (Component* comp, const bool undoable) if (comp != 0 && components.contains (comp)) { if (undoable) - perform (new FrontBackCompAction (comp, *this, -1), T("Move components to front")); + perform (new FrontBackCompAction (comp, *this, -1), "Move components to front"); else moveComponentZOrder (components.indexOf (comp), -1); } @@ -249,7 +249,7 @@ void ComponentLayout::componentToBack (Component* comp, const bool undoable) if (comp != 0 && components.contains (comp)) { if (undoable) - perform (new FrontBackCompAction (comp, *this, 0), T("Move components to back")); + perform (new FrontBackCompAction (comp, *this, 0), "Move components to back"); else moveComponentZOrder (components.indexOf (comp), 0); } @@ -257,7 +257,7 @@ void ComponentLayout::componentToBack (Component* comp, const bool undoable) //============================================================================== -const tchar* const ComponentLayout::clipboardXmlTag = T("COMPONENTS"); +const char* const ComponentLayout::clipboardXmlTag = "COMPONENTS"; void ComponentLayout::copySelectedToClipboard() { @@ -447,7 +447,7 @@ Component* ComponentLayout::findComponentWithId (const int64 componentId) const } //============================================================================== -static const tchar* const dimensionSuffixes[] = { T("X"), T("Y"), T("W"), T("H") }; +static const char* const dimensionSuffixes[] = { "X", "Y", "W", "H" }; Component* ComponentLayout::getComponentRelativePosTarget (Component* comp, int whichDimension) const { @@ -472,8 +472,7 @@ Component* ComponentLayout::getComponentRelativePosTarget (Component* comp, int } else { - return findComponentWithId (comp->getProperties() [String (T("relativeTo")) - + dimensionSuffixes [whichDimension]] + return findComponentWithId (comp->getProperties() [String ("relativeTo") + dimensionSuffixes [whichDimension]] .toString().getHexValue64()); } } @@ -560,8 +559,8 @@ PopupMenu ComponentLayout::getRelativeTargetMenu (Component* comp, int whichDime if (c != comp) { m.addItem (menuIdBase + i + 1, - T("Relative to ") + getComponentMemberVariableName (c) - + T(" (class: ") + ComponentTypeHandler::getHandlerFor (*c)->getClassName (c) + T(")"), + "Relative to " + getComponentMemberVariableName (c) + + " (class: " + ComponentTypeHandler::getHandlerFor (*c)->getClassName (c) + ")", ! dependsOnComponentForRelativePos (c, comp), current == c); } diff --git a/extras/the jucer/src/model/jucer_ComponentLayout.h b/extras/the jucer/src/model/jucer_ComponentLayout.h index c681196274..c4f410295f 100644 --- a/extras/the jucer/src/model/jucer_ComponentLayout.h +++ b/extras/the jucer/src/model/jucer_ComponentLayout.h @@ -87,7 +87,7 @@ public: //============================================================================== SelectedItemSet & getSelectedSet() { return selected; } - static const tchar* const clipboardXmlTag; + static const char* const clipboardXmlTag; void copySelectedToClipboard(); void paste(); void deleteSelected(); diff --git a/extras/the jucer/src/model/jucer_GeneratedCode.cpp b/extras/the jucer/src/model/jucer_GeneratedCode.cpp index e040748edd..af7ca2952d 100644 --- a/extras/the jucer/src/model/jucer_GeneratedCode.cpp +++ b/extras/the jucer/src/model/jucer_GeneratedCode.cpp @@ -51,11 +51,11 @@ String& GeneratedCode::getCallbackCode (const String& requiredParentClass, { String parentClass (requiredParentClass); if (parentClass.isNotEmpty() - && ! (parentClass.startsWith (T("public ")) - || parentClass.startsWith (T("private ")) - || parentClass.startsWith (T("protected ")))) + && ! (parentClass.startsWith ("public ") + || parentClass.startsWith ("private ") + || parentClass.startsWith ("protected "))) { - parentClass = T("public ") + parentClass; + parentClass = "public " + parentClass; } for (int i = callbacks.size(); --i >= 0;) @@ -91,7 +91,7 @@ void GeneratedCode::removeCallback (const String& returnType, const String& prot void GeneratedCode::addImageResourceLoader (const String& imageMemberName, const String& resourceName) { - const String initialiser (imageMemberName + T(" (0)")); + const String initialiser (imageMemberName + " (0)"); if (! initialisers.contains (initialiser, false)) { @@ -144,8 +144,8 @@ const String GeneratedCode::getCallbackDefinitions() const { CallbackMethod* const cm = callbacks.getUnchecked(i); - const String userCodeBlockName (T("User") - + makeValidCppIdentifier (cm->prototype.upToFirstOccurrenceOf (T("("), false, false), + const String userCodeBlockName ("User" + + makeValidCppIdentifier (cm->prototype.upToFirstOccurrenceOf ("(", false, false), true, true, false).trim()); if (userCodeBlockName.isNotEmpty() && cm->hasPrePostUserSections) @@ -180,13 +180,13 @@ const String GeneratedCode::getClassDeclaration() const parentClassLines.removeEmptyStrings(); parentClassLines.removeDuplicates (false); - if (parentClassLines.contains (T("public Button"), false)) - parentClassLines.removeString (("public Component"), false); + if (parentClassLines.contains ("public Button", false)) + parentClassLines.removeString ("public Component", false); - String r (T("class ")); - r << className << T(" : "); + String r ("class "); + r << className << " : "; - r += parentClassLines.joinIntoString (T(",\n") + String::repeatedString (T(" "), r.length())); + r += parentClassLines.joinIntoString (",\n" + String::repeatedString (" ", r.length())); return r; } @@ -213,7 +213,7 @@ const String GeneratedCode::getInitialiserList() const { String init (inits[i]); - while (init.endsWithChar (T(','))) + while (init.endsWithChar (',')) init = init.dropLastCharacters (1); s << init; @@ -246,7 +246,7 @@ static void replaceTemplate (String& text, const String& itemName, const String& { for (;;) { - const int index = text.indexOf (T("%%") + itemName + T("%%")); + const int index = text.indexOf ("%%" + itemName + "%%"); if (index < 0) break; @@ -255,7 +255,7 @@ static void replaceTemplate (String& text, const String& itemName, const String& for (int i = index; --i >= 0;) { - if (text[i] == T('\n')) + if (text[i] == '\n') break; ++indentLevel; @@ -269,12 +269,12 @@ static void replaceTemplate (String& text, const String& itemName, const String& //============================================================================== static bool getUserSection (const StringArray& lines, const String& tag, StringArray& resultLines) { - const int start = indexOfLineStartingWith (lines, T("//[") + tag + T("]"), 0); + const int start = indexOfLineStartingWith (lines, "//[" + tag + "]", 0); if (start < 0) return false; - const int end = indexOfLineStartingWith (lines, T("//[/") + tag + T("]"), start + 1); + const int end = indexOfLineStartingWith (lines, "//[/" + tag + "]", start + 1); for (int i = start + 1; i < end; ++i) resultLines.add (lines [i]); @@ -290,17 +290,17 @@ static void copyAcrossUserSections (String& dest, const String& src) for (int i = 0; i < dstLines.size(); ++i) { - if (dstLines[i].trimStart().startsWith (T("//["))) + if (dstLines[i].trimStart().startsWith ("//[")) { String tag (dstLines[i].trimStart().substring (3)); - tag = tag.upToFirstOccurrenceOf (T("]"), false, false); + tag = tag.upToFirstOccurrenceOf ("]", false, false); - jassert (! tag.startsWithChar (T('/'))); + jassert (! tag.startsWithChar ('/')); - if (! tag.startsWithChar (T('/'))) + if (! tag.startsWithChar ('/')) { const int endLine = indexOfLineStartingWith (dstLines, - T("//[/") + tag + T("]"), + "//[/" + tag + "]", i + 1); if (endLine > i) @@ -329,7 +329,7 @@ static void copyAcrossUserSections (String& dest, const String& src) dstLines.set (i, dstLines[i].trimEnd()); } - dest = dstLines.joinIntoString (T("\n")) + T("\n"); + dest = dstLines.joinIntoString ("\n") + "\n"; } //============================================================================== @@ -340,8 +340,8 @@ void GeneratedCode::applyToCode (String& code, { // header guard.. String headerGuard ("__JUCER_HEADER_"); - headerGuard << className.toUpperCase().retainCharacters (T("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) - << "_" << fileNameRoot.toUpperCase().retainCharacters (T("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) + headerGuard << className.toUpperCase().retainCharacters ("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + << "_" << fileNameRoot.toUpperCase().retainCharacters ("ABCDEFGHIJKLMNOPQRSTUVWXYZ") << "_" << String::toHexString (Random::getSystemRandom().nextInt()).toUpperCase() << "__"; replaceTemplate (code, "headerGuard", headerGuard); diff --git a/extras/the jucer/src/model/jucer_JucerDocument.cpp b/extras/the jucer/src/model/jucer_JucerDocument.cpp index 1dfe4b467b..3a96c5f7c7 100644 --- a/extras/the jucer/src/model/jucer_JucerDocument.cpp +++ b/extras/the jucer/src/model/jucer_JucerDocument.cpp @@ -28,16 +28,16 @@ #include "jucer_ObjectTypes.h" #include "../ui/jucer_TestComponent.h" -const tchar* const defaultClassName = T("NewJucerComponent"); -const tchar* const defaultParentClasses = T("public Component"); +const char* const defaultClassName = "NewJucerComponent"; +const char* const defaultParentClasses = "public Component"; static const int timerInterval = 150; //============================================================================== JucerDocument::JucerDocument() - : FileBasedDocument (T(".cpp"), T("*.cpp"), - T("Open a Jucer C++ file..."), - T("Save as a Jucer C++ file...")), + : FileBasedDocument (".cpp", "*.cpp", + "Open a Jucer C++ file...", + "Save as a Jucer C++ file..."), className (defaultClassName), parentClasses (defaultParentClasses), fixedSize (false), @@ -325,7 +325,7 @@ void JucerDocument::addExtraClassProperties (PropertyPanel* panel) } //============================================================================== -const tchar* const JucerDocument::jucerCompXmlTag = T("JUCER_COMPONENT"); +const char* const JucerDocument::jucerCompXmlTag = "JUCER_COMPONENT"; XmlElement* JucerDocument::createXml() const { @@ -376,21 +376,21 @@ bool JucerDocument::loadFromXml (const XmlElement& xml) initialWidth = xml.getIntAttribute (T("initialWidth"), 300); initialHeight = xml.getIntAttribute (T("initialHeight"), 200); - snapGridPixels = xml.getIntAttribute (T("snapPixels"), snapGridPixels); - snapActive = xml.getBoolAttribute (T("snapActive"), snapActive); - snapShown = xml.getBoolAttribute (T("snapShown"), snapShown); + snapGridPixels = xml.getIntAttribute ("snapPixels", snapGridPixels); + snapActive = xml.getBoolAttribute ("snapActive", snapActive); + snapShown = xml.getBoolAttribute ("snapShown", snapShown); - componentOverlayOpacity = (float) xml.getDoubleAttribute (T("overlayOpacity"), 0.0); + componentOverlayOpacity = (float) xml.getDoubleAttribute ("overlayOpacity", 0.0); activeExtraMethods.clear(); - XmlElement* const methods = xml.getChildByName T("METHODS"); + XmlElement* const methods = xml.getChildByName ("METHODS"); if (methods != 0) { - forEachXmlChildElementWithTagName (*methods, e, T("METHOD")) + forEachXmlChildElementWithTagName (*methods, e, "METHOD") { - activeExtraMethods.addIfNotAlreadyThere (e->getStringAttribute (T("name"))); + activeExtraMethods.addIfNotAlreadyThere (e->getStringAttribute ("name")); } } @@ -433,8 +433,8 @@ const String JucerDocument::loadDocument (const File& file) const String JucerDocument::saveDocument (const File& file) { - const File cppFile (file.withFileExtension (T(".cpp"))); - const File hFile (file.withFileExtension (T(".h"))); + const File cppFile (file.withFileExtension (".cpp")); + const File hFile (file.withFileExtension (".h")); String templateH, templateCpp; @@ -498,13 +498,13 @@ void JucerDocument::fillInGeneratedCode (GeneratedCode& code) const code.initialisers.addLines (variableInitialisers); if (! componentName.isEmpty()) - code.parentClassInitialiser = T("Component (") + quotedString (code.componentName) + T(")"); + code.parentClassInitialiser = "Component (" + quotedString (code.componentName) + ")"; // call these now, just to make sure they're the first two methods in the list. - code.getCallbackCode (String::empty, T("void"), T("paint (Graphics& g)"), false) + code.getCallbackCode (String::empty, "void", "paint (Graphics& g)", false) << "//[UserPrePaint] Add your own custom painting code here..\n//[/UserPrePaint]\n\n"; - code.getCallbackCode (String::empty, T("void"), T("resized()"), false); + code.getCallbackCode (String::empty, "void", "resized()", false); if (getComponentLayout() != 0) getComponentLayout()->fillInGeneratedCode (code); @@ -551,8 +551,8 @@ void JucerDocument::fillInGeneratedCode (GeneratedCode& code) const << "] -- Add your code here...\n" << initialContents[i]; - if (initialContents[i].isNotEmpty() && ! initialContents[i].endsWithChar (T('\n'))) - s << T('\n'); + if (initialContents[i].isNotEmpty() && ! initialContents[i].endsWithChar ('\n')) + s << '\n'; s << "//[/" << userCommentTag @@ -585,8 +585,8 @@ bool JucerDocument::findTemplateFiles (String& templateH, String& templateCpp) c templateH = hTemplate.loadFileAsString(); templateCpp = cppTemplate.loadFileAsString(); - const String jucerVersionString (T("Jucer version: ") + String (JUCER_MAJOR_VERSION) - + T(".") + String (JUCER_MINOR_VERSION)); + const String jucerVersionString ("Jucer version: " + String (JUCER_MAJOR_VERSION) + + "." + String (JUCER_MINOR_VERSION)); // This checks the template files to see if they're the ones that shipped with this // version of the jucer. If it fails, you're probably using the wrong ones. @@ -626,7 +626,7 @@ static const String fixNewLines (const String& s) while (lines.size() > 0 && lines [lines.size() - 1].trim().isEmpty()) lines.remove (lines.size() - 1); - return lines.joinIntoString (T("\r\n")) + T("\r\n"); + return lines.joinIntoString ("\r\n") + "\r\n"; } bool JucerDocument::writeCodeFiles (const File& headerFile, diff --git a/extras/the jucer/src/model/jucer_JucerDocument.h b/extras/the jucer/src/model/jucer_JucerDocument.h index eedb730dc7..1d7d0f0f34 100644 --- a/extras/the jucer/src/model/jucer_JucerDocument.h +++ b/extras/the jucer/src/model/jucer_JucerDocument.h @@ -124,7 +124,7 @@ public: float getComponentOverlayOpacity() const throw() { return componentOverlayOpacity; } //============================================================================== - static const tchar* const jucerCompXmlTag; + static const char* const jucerCompXmlTag; /** Creates the document's metadata xml section. diff --git a/extras/the jucer/src/model/jucer_ObjectTypes.cpp b/extras/the jucer/src/model/jucer_ObjectTypes.cpp index 39f76c2223..7d276bdbe4 100644 --- a/extras/the jucer/src/model/jucer_ObjectTypes.cpp +++ b/extras/the jucer/src/model/jucer_ObjectTypes.cpp @@ -58,14 +58,14 @@ namespace ObjectTypes { //============================================================================== -static const tchar* const documentNames[] = +static const char* const documentNames[] = { - T("Component"), - T("Button"), + "Component", + "Button", 0 }; -const tchar** const documentTypeNames = (const tchar**) documentNames; +const char** const documentTypeNames = (const char**) documentNames; const int numDocumentTypes = numElementsInArray (documentNames) - 1; JucerDocument* createNewDocument (const int index) @@ -142,18 +142,18 @@ JucerDocument* loadDocumentFromFile (const File& f, const bool showErrorMessage) } //============================================================================== -static const tchar* const elementNames[] = +static const char* const elementNames[] = { - T("Rectangle"), - T("Rounded Rectangle"), - T("Ellipse"), - T("Path"), - T("Image"), - T("Text"), + "Rectangle", + "Rounded Rectangle", + "Ellipse", + "Path", + "Image", + "Text", 0 }; -const tchar** const elementTypeNames = (const tchar**) elementNames; +const char** const elementTypeNames = (const char**) elementNames; const int numElementTypes = (sizeof (elementNames) / sizeof (elementNames[0])) - 1; PaintElement* createNewElement (const int index, PaintRoutine* owner) diff --git a/extras/the jucer/src/model/jucer_ObjectTypes.h b/extras/the jucer/src/model/jucer_ObjectTypes.h index c404285bbb..41193820ea 100644 --- a/extras/the jucer/src/model/jucer_ObjectTypes.h +++ b/extras/the jucer/src/model/jucer_ObjectTypes.h @@ -42,7 +42,7 @@ namespace ObjectTypes /** Documents. */ - extern const tchar** const documentTypeNames; + extern const char** const documentTypeNames; extern const int numDocumentTypes; JucerDocument* createNewDocument (const int index); @@ -59,7 +59,7 @@ namespace ObjectTypes /** Elements. */ - extern const tchar** const elementTypeNames; + extern const char** const elementTypeNames; extern const int numElementTypes; PaintElement* createNewElement (const int index, PaintRoutine* owner); diff --git a/extras/the jucer/src/model/jucer_PaintRoutine.cpp b/extras/the jucer/src/model/jucer_PaintRoutine.cpp index 6196a52fff..425eefb6a9 100644 --- a/extras/the jucer/src/model/jucer_PaintRoutine.cpp +++ b/extras/the jucer/src/model/jucer_PaintRoutine.cpp @@ -146,7 +146,7 @@ PaintElement* PaintRoutine::addElementFromXml (const XmlElement& xml, const int if (undoable) { AddXmlElementAction* action = new AddXmlElementAction (*this, new XmlElement (xml)); - perform (action, T("Add new element")); + perform (action, "Add new element"); return elements [action->indexAdded]; } @@ -291,7 +291,7 @@ void PaintRoutine::elementToFront (PaintElement* element, const bool undoable) if (element != 0 && elements.contains (element)) { if (undoable) - perform (new FrontOrBackElementAction (element, -1), T("Move elements to front")); + perform (new FrontOrBackElementAction (element, -1), "Move elements to front"); else moveElementZOrder (elements.indexOf (element), -1); } @@ -302,14 +302,14 @@ void PaintRoutine::elementToBack (PaintElement* element, const bool undoable) if (element != 0 && elements.contains (element)) { if (undoable) - perform (new FrontOrBackElementAction (element, 0), T("Move elements to back")); + perform (new FrontOrBackElementAction (element, 0), "Move elements to back"); else moveElementZOrder (elements.indexOf (element), 0); } } //============================================================================== -const tchar* const PaintRoutine::clipboardXmlTag = T("PAINTELEMENTS"); +const char* const PaintRoutine::clipboardXmlTag = "PAINTELEMENTS"; void PaintRoutine::copySelectedToClipboard() { @@ -585,7 +585,7 @@ void PaintRoutine::dropImageAt (const File& f, int x, int y) } //============================================================================== -const tchar* PaintRoutine::xmlTagName = T("BACKGROUND"); +const char* PaintRoutine::xmlTagName = "BACKGROUND"; XmlElement* PaintRoutine::createXml() const { diff --git a/extras/the jucer/src/model/jucer_PaintRoutine.h b/extras/the jucer/src/model/jucer_PaintRoutine.h index 7c7af7302f..f0038b4af8 100644 --- a/extras/the jucer/src/model/jucer_PaintRoutine.h +++ b/extras/the jucer/src/model/jucer_PaintRoutine.h @@ -74,7 +74,7 @@ public: SelectedItemSet & getSelectedElements() throw() { return selectedElements; } SelectedItemSet & getSelectedPoints() throw() { return selectedPoints; } - static const tchar* const clipboardXmlTag; + static const char* const clipboardXmlTag; void copySelectedToClipboard(); void paste(); void deleteSelected(); @@ -97,7 +97,7 @@ public: JucerDocument* getDocument() const throw() { return document; } //============================================================================== - static const tchar* xmlTagName; + static const char* xmlTagName; XmlElement* createXml() const; bool loadFromXml (const XmlElement& xml); diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementEllipse.h b/extras/the jucer/src/model/paintelements/jucer_PaintElementEllipse.h index e558591eda..52f753619f 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementEllipse.h +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementEllipse.h @@ -99,7 +99,7 @@ public: } } - static const tchar* getTagName() throw() { return T("ELLIPSE"); } + static const char* getTagName() throw() { return "ELLIPSE"; } XmlElement* createXml() const { diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementGroup.h b/extras/the jucer/src/model/paintelements/jucer_PaintElementGroup.h index b55a17f2c2..c4bbee3963 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementGroup.h +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementGroup.h @@ -193,7 +193,7 @@ public: subElements.getUnchecked(i)->fillInGeneratedCode (code, paintMethodCode); } - static const tchar* getTagName() throw() { return T("GROUP"); } + static const char* getTagName() throw() { return "GROUP"; } XmlElement* createXml() const { diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementImage.h b/extras/the jucer/src/model/paintelements/jucer_PaintElementImage.h index 2d4daeaa8d..5ef25755ac 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementImage.h +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementImage.h @@ -153,7 +153,7 @@ public: { if (resourceName.isNotEmpty()) { - const String imageVariable (T("drawable") + String (code.getUniqueSuffix())); + const String imageVariable (L"drawable" + String (code.getUniqueSuffix())); code.privateMemberDeclarations << "Drawable* " << imageVariable << ";\n"; @@ -299,7 +299,7 @@ public: double getOpacity() const throw() { return opacity; } //============================================================================== - static const tchar* getTagName() throw() { return T("IMAGE"); } + static const char* getTagName() throw() { return "IMAGE"; } void resetToImageSize() { diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.cpp b/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.cpp index b40e9eee2c..e3eb9ac4c5 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.cpp +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.cpp @@ -380,7 +380,7 @@ void PaintElementPath::fillInGeneratedCode (GeneratedCode& code, String& paintMe if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent)) return; - const String pathVariable (T("internalPath") + String (code.getUniqueSuffix())); + const String pathVariable ("internalPath" + String (code.getUniqueSuffix())); const ComponentLayout* layout = code.document->getComponentLayout(); @@ -1196,14 +1196,14 @@ class PathPointTypeProperty : public ChoicePropertyComponent, public: PathPointTypeProperty (PaintElementPath* const owner_, const int index_) - : ChoicePropertyComponent (T("point type")), + : ChoicePropertyComponent ("point type"), owner (owner_), index (index_) { - choices.add (T("Start of sub-path")); - choices.add (T("Line")); - choices.add (T("Quadratic")); - choices.add (T("Cubic")); + choices.add ("Start of sub-path"); + choices.add ("Line"); + choices.add ("Quadratic"); + choices.add ("Cubic"); owner->getDocument()->addChangeListener (this); } @@ -1330,14 +1330,14 @@ class PathPointClosedProperty : public ChoicePropertyComponent, { public: PathPointClosedProperty (PaintElementPath* const owner_, const int index_) - : ChoicePropertyComponent (T("openness")), + : ChoicePropertyComponent ("openness"), owner (owner_), index (index_) { owner->getDocument()->addChangeListener (this); - choices.add (T("Subpath is closed")); - choices.add (T("Subpath is open-ended")); + choices.add ("Subpath is closed"); + choices.add ("Subpath is open-ended"); } ~PathPointClosedProperty() @@ -1370,7 +1370,7 @@ class AddNewPointProperty : public ButtonPropertyComponent { public: AddNewPointProperty (PaintElementPath* const owner_, const int index_) - : ButtonPropertyComponent (T("new point"), false), + : ButtonPropertyComponent ("new point", false), owner (owner_), index (index_) { @@ -1383,7 +1383,7 @@ public: owner->addPoint (index, true); } - const String getButtonText() const { return T("Add new point"); } + const String getButtonText() const { return "Add new point"; } private: PaintElementPath* const owner; @@ -1492,7 +1492,7 @@ void PathPoint::changePointType (const Path::Iterator::PathElementType newType, if (undoable) { owner->perform (new ChangePointAction (this, withChangedPointType (newType, parentArea)), - T("Change path point type")); + "Change path point type"); } else { @@ -1510,8 +1510,8 @@ void PathPoint::getEditableProperties (Array & properties) switch (type) { case Path::Iterator::startNewSubPath: - properties.add (new PathPointPositionProperty (owner, index, 0, T("x"), PositionPropertyBase::componentX)); - properties.add (new PathPointPositionProperty (owner, index, 0, T("y"), PositionPropertyBase::componentY)); + properties.add (new PathPointPositionProperty (owner, index, 0, "x", PositionPropertyBase::componentX)); + properties.add (new PathPointPositionProperty (owner, index, 0, "y", PositionPropertyBase::componentY)); properties.add (new PathPointClosedProperty (owner, index)); properties.add (new AddNewPointProperty (owner, index)); @@ -1519,28 +1519,28 @@ void PathPoint::getEditableProperties (Array & properties) case Path::Iterator::lineTo: properties.add (new PathPointTypeProperty (owner, index)); - properties.add (new PathPointPositionProperty (owner, index, 0, T("x"), PositionPropertyBase::componentX)); - properties.add (new PathPointPositionProperty (owner, index, 0, T("y"), PositionPropertyBase::componentY)); + properties.add (new PathPointPositionProperty (owner, index, 0, "x", PositionPropertyBase::componentX)); + properties.add (new PathPointPositionProperty (owner, index, 0, "y", PositionPropertyBase::componentY)); properties.add (new AddNewPointProperty (owner, index)); break; case Path::Iterator::quadraticTo: properties.add (new PathPointTypeProperty (owner, index)); - properties.add (new PathPointPositionProperty (owner, index, 0, T("control pt x"), PositionPropertyBase::componentX)); - properties.add (new PathPointPositionProperty (owner, index, 0, T("control pt y"), PositionPropertyBase::componentY)); - properties.add (new PathPointPositionProperty (owner, index, 1, T("x"), PositionPropertyBase::componentX)); - properties.add (new PathPointPositionProperty (owner, index, 1, T("y"), PositionPropertyBase::componentY)); + properties.add (new PathPointPositionProperty (owner, index, 0, "control pt x", PositionPropertyBase::componentX)); + properties.add (new PathPointPositionProperty (owner, index, 0, "control pt y", PositionPropertyBase::componentY)); + properties.add (new PathPointPositionProperty (owner, index, 1, "x", PositionPropertyBase::componentX)); + properties.add (new PathPointPositionProperty (owner, index, 1, "y", PositionPropertyBase::componentY)); properties.add (new AddNewPointProperty (owner, index)); break; case Path::Iterator::cubicTo: properties.add (new PathPointTypeProperty (owner, index)); - properties.add (new PathPointPositionProperty (owner, index, 0, T("control pt1 x"), PositionPropertyBase::componentX)); - properties.add (new PathPointPositionProperty (owner, index, 0, T("control pt1 y"), PositionPropertyBase::componentY)); - properties.add (new PathPointPositionProperty (owner, index, 1, T("control pt2 x"), PositionPropertyBase::componentX)); - properties.add (new PathPointPositionProperty (owner, index, 1, T("control pt2 y"), PositionPropertyBase::componentY)); - properties.add (new PathPointPositionProperty (owner, index, 2, T("x"), PositionPropertyBase::componentX)); - properties.add (new PathPointPositionProperty (owner, index, 2, T("y"), PositionPropertyBase::componentY)); + properties.add (new PathPointPositionProperty (owner, index, 0, "control pt1 x", PositionPropertyBase::componentX)); + properties.add (new PathPointPositionProperty (owner, index, 0, "control pt1 y", PositionPropertyBase::componentY)); + properties.add (new PathPointPositionProperty (owner, index, 1, "control pt2 x", PositionPropertyBase::componentX)); + properties.add (new PathPointPositionProperty (owner, index, 1, "control pt2 y", PositionPropertyBase::componentY)); + properties.add (new PathPointPositionProperty (owner, index, 2, "x", PositionPropertyBase::componentX)); + properties.add (new PathPointPositionProperty (owner, index, 2, "y", PositionPropertyBase::componentY)); properties.add (new AddNewPointProperty (owner, index)); break; diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.h b/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.h index 56ce0d3cf5..3ac9a559e1 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.h +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementPath.h @@ -116,7 +116,7 @@ public: void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode); //============================================================================== - static const tchar* getTagName() throw() { return T("PATH"); } + static const char* getTagName() throw() { return "PATH"; } XmlElement* createXml() const; bool loadFromXml (const XmlElement& xml); diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementRectangle.h b/extras/the jucer/src/model/paintelements/jucer_PaintElementRectangle.h index 5ea81d0f18..cbd34bdf33 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementRectangle.h +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementRectangle.h @@ -37,7 +37,7 @@ class PaintElementRectangle : public ColouredElement public: //============================================================================== PaintElementRectangle (PaintRoutine* owner) - : ColouredElement (owner, T("Rectangle"), true, false) + : ColouredElement (owner, "Rectangle", true, false) { } @@ -107,7 +107,7 @@ public: } } - static const tchar* getTagName() throw() { return T("RECT"); } + static const char* getTagName() throw() { return "RECT"; } XmlElement* createXml() const { @@ -154,7 +154,7 @@ private: { public: ShapeToPathProperty (PaintElementRectangle* const element_) - : ButtonPropertyComponent (T("path"), false), + : ButtonPropertyComponent ("path", false), element (element_) { } @@ -166,7 +166,7 @@ private: const String getButtonText() const { - return T("convert to a path"); + return "convert to a path"; } private: diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementRoundedRectangle.h b/extras/the jucer/src/model/paintelements/jucer_PaintElementRoundedRectangle.h index 04014b271b..a4e50ab74d 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementRoundedRectangle.h +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementRoundedRectangle.h @@ -156,7 +156,7 @@ public: } } - static const tchar* getTagName() throw() { return T("ROUNDRECT"); } + static const char* getTagName() throw() { return "ROUNDRECT"; } XmlElement* createXml() const { diff --git a/extras/the jucer/src/model/paintelements/jucer_PaintElementText.h b/extras/the jucer/src/model/paintelements/jucer_PaintElementText.h index a4129f7ead..8b19a52435 100644 --- a/extras/the jucer/src/model/paintelements/jucer_PaintElementText.h +++ b/extras/the jucer/src/model/paintelements/jucer_PaintElementText.h @@ -105,19 +105,19 @@ public: } } - static const tchar* getTagName() throw() { return T("TEXT"); } + static const char* getTagName() throw() { return "TEXT"; } XmlElement* createXml() const { XmlElement* e = new XmlElement (getTagName()); position.applyToXml (*e); addColourAttributes (e); - e->setAttribute (T("text"), text); - e->setAttribute (T("fontname"), typefaceName); - e->setAttribute (T("fontsize"), roundToInt (font.getHeight() * 100.0) / 100.0); - e->setAttribute (T("bold"), font.isBold()); - e->setAttribute (T("italic"), font.isItalic()); - e->setAttribute (T("justification"), justification.getFlags()); + e->setAttribute ("text", text); + e->setAttribute ("fontname", typefaceName); + e->setAttribute ("fontsize", roundToInt (font.getHeight() * 100.0) / 100.0); + e->setAttribute ("bold", font.isBold()); + e->setAttribute ("italic", font.isItalic()); + e->setAttribute ("justification", justification.getFlags()); return e; } @@ -129,12 +129,12 @@ public: position.restoreFromXml (xml, position); loadColourAttributes (xml); - text = xml.getStringAttribute (T("text"), T("Hello World")); - typefaceName = xml.getStringAttribute (T("fontname"), FontPropertyComponent::defaultFont); - font.setHeight ((float) xml.getDoubleAttribute (T("fontsize"), 15.0)); - font.setBold (xml.getBoolAttribute (T("bold"), false)); - font.setItalic (xml.getBoolAttribute (T("italic"), false)); - justification = Justification (xml.getIntAttribute (T("justification"), Justification::centred)); + text = xml.getStringAttribute ("text", "Hello World"); + typefaceName = xml.getStringAttribute ("fontname", FontPropertyComponent::defaultFont); + font.setHeight ((float) xml.getDoubleAttribute ("fontsize", 15.0)); + font.setBold (xml.getBoolAttribute ("bold", false)); + font.setItalic (xml.getBoolAttribute ("italic", false)); + justification = Justification (xml.getIntAttribute ("justification", Justification::centred)); return true; } @@ -183,7 +183,7 @@ public: if (undoable) { perform (new SetTextAction (this, t), - T("Change text element text")); + "Change text element text"); } else { @@ -231,7 +231,7 @@ public: if (undoable) { perform (new SetFontAction (this, newFont), - T("Change text element font")); + "Change text element font"); } else { @@ -275,7 +275,7 @@ public: if (undoable) { perform (new SetTypefaceAction (this, newFontName), - T("Change text element typeface")); + "Change text element typeface"); } else { @@ -324,7 +324,7 @@ public: if (undoable) { perform (new SetJustifyAction (this, j), - T("Change text element justification")); + "Change text element justification"); } else { @@ -373,7 +373,7 @@ private: { public: TextProperty (PaintElementText* const element_) - : TextPropertyComponent (T("text"), 2048, false), + : TextPropertyComponent ("text", 2048, false), element (element_) { element->getDocument()->addChangeListener (this); @@ -399,7 +399,7 @@ private: { public: FontNameProperty (PaintElementText* const element_) - : FontPropertyComponent (T("font")), + : FontPropertyComponent ("font"), element (element_) { element->getDocument()->addChangeListener (this); @@ -425,15 +425,15 @@ private: { public: FontStyleProperty (PaintElementText* const element_) - : ChoicePropertyComponent (T("style")), + : ChoicePropertyComponent ("style"), element (element_) { element->getDocument()->addChangeListener (this); - choices.add (T("normal")); - choices.add (T("bold")); - choices.add (T("italic")); - choices.add (T("bold + italic")); + choices.add ("normal"); + choices.add ("bold"); + choices.add ("italic"); + choices.add ("bold + italic"); } ~FontStyleProperty() @@ -475,7 +475,7 @@ private: { public: FontSizeProperty (PaintElementText* const element_) - : SliderPropertyComponent (T("size"), 1.0, 250.0, 0.1, 0.3), + : SliderPropertyComponent ("size", 1.0, 250.0, 0.1, 0.3), element (element_) { element->getDocument()->addChangeListener (this); @@ -513,7 +513,7 @@ private: { public: TextJustificationProperty (PaintElementText* const element_) - : JustificationProperty (T("layout"), false), + : JustificationProperty ("layout", false), element (element_) { element->getDocument()->addChangeListener (this); @@ -545,7 +545,7 @@ private: { public: TextToPathProperty (PaintElementText* const element_) - : ButtonPropertyComponent (T("path"), false), + : ButtonPropertyComponent ("path", false), element (element_) { } @@ -557,7 +557,7 @@ private: const String getButtonText() const { - return T("convert text to a path"); + return "convert text to a path"; } private: diff --git a/extras/the jucer/src/properties/jucer_JustificationProperty.h b/extras/the jucer/src/properties/jucer_JustificationProperty.h index afe249a46f..34639076eb 100644 --- a/extras/the jucer/src/properties/jucer_JustificationProperty.h +++ b/extras/the jucer/src/properties/jucer_JustificationProperty.h @@ -39,21 +39,21 @@ public: { if (onlyHorizontalOptions) { - choices.add (T("centre")); - choices.add (T("left")); - choices.add (T("right")); + choices.add ("centre"); + choices.add ("left"); + choices.add ("right"); } else { - choices.add (T("centred")); - choices.add (T("centred left")); - choices.add (T("centred right")); - choices.add (T("centred top")); - choices.add (T("centred bottom")); - choices.add (T("top left")); - choices.add (T("top right")); - choices.add (T("bottom left")); - choices.add (T("bottom right")); + choices.add ("centred"); + choices.add ("centred left"); + choices.add ("centred right"); + choices.add ("centred top"); + choices.add ("centred bottom"); + choices.add ("top left"); + choices.add ("top right"); + choices.add ("bottom left"); + choices.add ("bottom right"); } } diff --git a/extras/the jucer/src/properties/jucer_PositionPropertyBase.h b/extras/the jucer/src/properties/jucer_PositionPropertyBase.h index a42962b2ce..1ab375b51d 100644 --- a/extras/the jucer/src/properties/jucer_PositionPropertyBase.h +++ b/extras/the jucer/src/properties/jucer_PositionPropertyBase.h @@ -82,28 +82,28 @@ public: { case componentX: if (p.getPositionModeX() == PositionedRectangle::proportionOfParentSize) - s << valueToString (p.getX() * 100.0) << T('%'); + s << valueToString (p.getX() * 100.0) << '%'; else s << valueToString (p.getX()); break; case componentY: if (p.getPositionModeY() == PositionedRectangle::proportionOfParentSize) - s << valueToString (p.getY() * 100.0) << T('%'); + s << valueToString (p.getY() * 100.0) << '%'; else s << valueToString (p.getY()); break; case componentWidth: if (p.getWidthMode() == PositionedRectangle::proportionalSize) - s << valueToString (p.getWidth() * 100.0) << T('%'); + s << valueToString (p.getWidth() * 100.0) << '%'; else s << valueToString (p.getWidth()); break; case componentHeight: if (p.getHeightMode() == PositionedRectangle::proportionalSize) - s << valueToString (p.getHeight() * 100.0) << T('%'); + s << valueToString (p.getHeight() * 100.0) << '%'; else s << valueToString (p.getHeight()); break; @@ -237,16 +237,16 @@ public: { const PositionedRectangle::SizeMode sizeMode = (dimension == componentWidth) ? sizeW : sizeH; - m.addItem (20, (dimension == componentWidth) ? T("Absolute width") - : T("Absolute height"), + m.addItem (20, (dimension == componentWidth) ? "Absolute width" + : "Absolute height", true, sizeMode == PositionedRectangle::absoluteSize); - m.addItem (21, ((dimension == componentWidth) ? T("Percentage of width of ") - : T("Percentage of height of ")) + relCompName, + m.addItem (21, ((dimension == componentWidth) ? "Percentage of width of " + : "Percentage of height of ") + relCompName, true, sizeMode == PositionedRectangle::proportionalSize); - m.addItem (22, ((dimension == componentWidth) ? T("Subtracted from width of ") - : T("Subtracted from height of ")) + relCompName, + m.addItem (22, ((dimension == componentWidth) ? "Subtracted from width of " + : "Subtracted from height of ") + relCompName, true, sizeMode == PositionedRectangle::parentSizeMinusAbsolute); } @@ -254,7 +254,7 @@ public: if (allowRelativeOptions && layout != 0) { m.addSeparator(); - m.addSubMenu (T("Relative to"), layout->getRelativeTargetMenu (component, (int) dimension)); + m.addSubMenu ("Relative to", layout->getRelativeTargetMenu (component, (int) dimension)); } const int menuResult = m.showAt (button); diff --git a/extras/the jucer/src/ui/jucer_CommandIDs.h b/extras/the jucer/src/ui/jucer_CommandIDs.h index 5522487cee..2a9b24d21c 100644 --- a/extras/the jucer/src/ui/jucer_CommandIDs.h +++ b/extras/the jucer/src/ui/jucer_CommandIDs.h @@ -70,7 +70,7 @@ namespace CommandIDs namespace CommandCategories { - static const tchar* const general = T("General"); - static const tchar* const editing = T("Editing"); - static const tchar* const view = T("View"); + static const char* const general = "General"; + static const char* const editing = "Editing"; + static const char* const view = "View"; } diff --git a/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp b/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp index 0c842a0090..371cd5a921 100644 --- a/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp +++ b/extras/the jucer/src/ui/jucer_ComponentLayoutEditor.cpp @@ -354,14 +354,14 @@ bool ComponentLayoutEditor::keyPressed (const KeyPress& key) bool ComponentLayoutEditor::isInterestedInFileDrag (const StringArray& filenames) { const File f (filenames [0]); - return f.hasFileExtension (T(".cpp")); + return f.hasFileExtension (".cpp"); } void ComponentLayoutEditor::filesDropped (const StringArray& filenames, int x, int y) { const File f (filenames [0]); - if (f.hasFileExtension (T(".cpp"))) + if (f.hasFileExtension (".cpp")) { JucerDocument* doc = ObjectTypes::loadDocumentFromFile (f, false); diff --git a/extras/the jucer/src/ui/jucer_ComponentOverlayComponent.cpp b/extras/the jucer/src/ui/jucer_ComponentOverlayComponent.cpp index dff4215b54..1d5037e7bb 100644 --- a/extras/the jucer/src/ui/jucer_ComponentOverlayComponent.cpp +++ b/extras/the jucer/src/ui/jucer_ComponentOverlayComponent.cpp @@ -170,7 +170,7 @@ void ComponentOverlayComponent::resizeStart() else originalAspectRatio = 1.0; - layout.getDocument()->getUndoManager().beginNewTransaction (T("Resize components")); + layout.getDocument()->getUndoManager().beginNewTransaction ("Resize components"); } void ComponentOverlayComponent::resizeEnd() diff --git a/extras/the jucer/src/ui/jucer_JucerDocumentHolder.cpp b/extras/the jucer/src/ui/jucer_JucerDocumentHolder.cpp index 5e6d84e0ee..578d322ec3 100644 --- a/extras/the jucer/src/ui/jucer_JucerDocumentHolder.cpp +++ b/extras/the jucer/src/ui/jucer_JucerDocumentHolder.cpp @@ -763,8 +763,8 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application { const int index = commandID - CommandIDs::newComponentBase; - result.setInfo (T("New ") + ObjectTypes::componentTypeHandlers [index]->getTypeName(), - T("Creates a new ") + ObjectTypes::componentTypeHandlers [index]->getTypeName(), + result.setInfo ("New " + ObjectTypes::componentTypeHandlers [index]->getTypeName(), + "Creates a new " + ObjectTypes::componentTypeHandlers [index]->getTypeName(), CommandCategories::editing, 0); return; } @@ -774,8 +774,8 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application { const int index = commandID - CommandIDs::newElementBase; - result.setInfo (String (T("New ")) + ObjectTypes::elementTypeNames [index], - String (T("Adds a new ")) + ObjectTypes::elementTypeNames [index], + result.setInfo (String ("New ") + ObjectTypes::elementTypeNames [index], + String ("Adds a new ") + ObjectTypes::elementTypeNames [index], CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0); @@ -795,7 +795,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Saves the current component."), CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress (T('s'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('s', cmd, 0)); break; @@ -803,7 +803,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application result.setInfo (T("Save As..."), T("Saves the current component to a specified file."), CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress (T('s'), cmd | shift, 0)); + result.defaultKeypresses.add (KeyPress ('s', cmd | shift, 0)); break; case CommandIDs::undo: @@ -811,7 +811,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Undoes the last operation."), CommandCategories::editing, 0); result.setActive (document->getUndoManager().canUndo()); - result.defaultKeypresses.add (KeyPress (T('z'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('z', cmd, 0)); break; case CommandIDs::redo: @@ -819,8 +819,8 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Redoes the last operation."), CommandCategories::editing, 0); result.setActive (document->getUndoManager().canRedo()); - result.defaultKeypresses.add (KeyPress (T('z'), cmd | shift, 0)); - result.defaultKeypresses.add (KeyPress (T('y'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('z', cmd | shift, 0)); + result.defaultKeypresses.add (KeyPress ('y', cmd, 0)); break; case CommandIDs::toFront: @@ -828,7 +828,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Brings the currently selected component to the front."), CommandCategories::editing, 0); result.setActive (isSomethingSelected()); - result.defaultKeypresses.add (KeyPress (T('f'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('f', cmd, 0)); break; case CommandIDs::toBack: @@ -836,7 +836,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Sends the currently selected component to the back."), CommandCategories::editing, 0); result.setActive (isSomethingSelected()); - result.defaultKeypresses.add (KeyPress (T('b'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('b', cmd, 0)); break; case CommandIDs::group: @@ -845,7 +845,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0 && currentPaintRoutine->getSelectedElements().getNumSelected() > 1); - result.defaultKeypresses.add (KeyPress (T('k'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('k', cmd, 0)); break; case CommandIDs::ungroup: @@ -855,14 +855,14 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application result.setActive (currentPaintRoutine != 0 && currentPaintRoutine->getSelectedElements().getNumSelected() == 1 && currentPaintRoutine->getSelectedElements().getSelectedItem (0)->getTypeName() == T("Group")); - result.defaultKeypresses.add (KeyPress (T('k'), cmd | shift, 0)); + result.defaultKeypresses.add (KeyPress ('k', cmd | shift, 0)); break; case CommandIDs::test: result.setInfo (T("Test component..."), T("Runs the current component interactively."), CommandCategories::view, 0); - result.defaultKeypresses.add (KeyPress (T('t'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('t', cmd, 0)); break; case CommandIDs::enableSnapToGrid: @@ -870,7 +870,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Toggles whether components' positions are aligned to a grid."), CommandCategories::view, 0); result.setTicked (document->isSnapActive (false)); - result.defaultKeypresses.add (KeyPress (T('g'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('g', cmd, 0)); break; case CommandIDs::showGrid: @@ -878,7 +878,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Toggles whether the snapping grid is displayed on-screen."), CommandCategories::view, 0); result.setTicked (document->isSnapShown()); - result.defaultKeypresses.add (KeyPress (T('g'), cmd | shift, 0)); + result.defaultKeypresses.add (KeyPress ('g', cmd | shift, 0)); break; case CommandIDs::editCompLayout: @@ -887,7 +887,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application CommandCategories::view, 0); result.setActive (tabbedComponent != 0); result.setTicked (currentLayout != 0); - result.defaultKeypresses.add (KeyPress (T('n'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('n', cmd, 0)); break; case CommandIDs::editCompGraphics: @@ -896,7 +896,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application CommandCategories::view, 0); result.setActive (tabbedComponent != 0); result.setTicked (currentPaintRoutine != 0); - result.defaultKeypresses.add (KeyPress (T('m'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('m', cmd, 0)); break; case CommandIDs::bringBackLostItems: @@ -904,7 +904,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Moves any items that are lost beyond the edges of the screen back to the centre."), CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0 || currentLayout != 0); - result.defaultKeypresses.add (KeyPress (T('m'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('m', cmd, 0)); break; case CommandIDs::zoomIn: @@ -912,7 +912,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Zooms in on the current component."), CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0 || currentLayout != 0); - result.defaultKeypresses.add (KeyPress (T(']'), cmd, 0)); + result.defaultKeypresses.add (KeyPress (']', cmd, 0)); break; case CommandIDs::zoomOut: @@ -920,7 +920,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Zooms out on the current component."), CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0 || currentLayout != 0); - result.defaultKeypresses.add (KeyPress (T('['), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('[', cmd, 0)); break; case CommandIDs::zoomNormal: @@ -928,7 +928,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Restores the zoom level to normal."), CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0 || currentLayout != 0); - result.defaultKeypresses.add (KeyPress (T('1'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('1', cmd, 0)); break; case CommandIDs::spaceBarDrag: @@ -962,7 +962,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application num = 3; } - result.defaultKeypresses.add (KeyPress (T('2') + num, cmd, 0)); + result.defaultKeypresses.add (KeyPress ('2' + num, cmd, 0)); int currentAmount = 0; if (document->getComponentOverlayOpacity() > 0.9f) @@ -987,7 +987,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Copies the currently selected components to the clipboard and deletes them."), CommandCategories::editing, 0); result.setActive (isSomethingSelected()); - result.defaultKeypresses.add (KeyPress (T('x'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('x', cmd, 0)); break; case StandardApplicationCommandIDs::copy: @@ -995,7 +995,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Copies the currently selected components to the clipboard."), CommandCategories::editing, 0); result.setActive (isSomethingSelected()); - result.defaultKeypresses.add (KeyPress (T('c'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('c', cmd, 0)); break; case StandardApplicationCommandIDs::paste: @@ -1003,7 +1003,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application result.setInfo (T("Paste"), T("Pastes any components from the clipboard."), CommandCategories::editing, 0); - result.defaultKeypresses.add (KeyPress (T('v'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('v', cmd, 0)); bool canPaste = false; XmlDocument clip (SystemClipboard::getTextFromClipboard()); @@ -1038,7 +1038,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Selects all of whatever item is currently selected."), CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0 || currentLayout != 0); - result.defaultKeypresses.add (KeyPress (T('a'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('a', cmd, 0)); break; case StandardApplicationCommandIDs::deselectAll: @@ -1046,7 +1046,7 @@ void JucerDocumentHolder::getCommandInfo (const CommandID commandID, Application T("Deselects whatever is currently selected."), CommandCategories::editing, 0); result.setActive (currentPaintRoutine != 0 || currentLayout != 0); - result.defaultKeypresses.add (KeyPress (T('d'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('d', cmd, 0)); break; default: diff --git a/extras/the jucer/src/ui/jucer_MainWindow.cpp b/extras/the jucer/src/ui/jucer_MainWindow.cpp index 857287539d..6e72deb7bb 100644 --- a/extras/the jucer/src/ui/jucer_MainWindow.cpp +++ b/extras/the jucer/src/ui/jucer_MainWindow.cpp @@ -201,7 +201,7 @@ bool MainWindow::isInterestedInFileDrag (const StringArray& filenames) { const File f (filenames[i]); - if (f.hasFileExtension (T(".cpp"))) + if (f.hasFileExtension (".cpp")) return true; } @@ -214,7 +214,7 @@ void MainWindow::filesDropped (const StringArray& filenames, int mouseX, int mou { const File f (filenames[i]); - if (f.hasFileExtension (T(".cpp")) && openFile (f)) + if (f.hasFileExtension (".cpp") && openFile (f)) break; } } @@ -230,9 +230,9 @@ void MainWindow::activeWindowStatusChanged() //============================================================================== const StringArray MainWindow::getMenuBarNames() { - const tchar* const names[] = { T("File"), T("Edit"), T("View"), 0 }; + const char* const names[] = { "File", "Edit", "View", 0 }; - return StringArray ((const tchar**) names); + return StringArray (names); } const PopupMenu MainWindow::getMenuForIndex (int topLevelMenuIndex, @@ -311,11 +311,11 @@ const PopupMenu MainWindow::getMenuForIndex (int topLevelMenuIndex, menu.addCommandItem (commandManager, CommandIDs::test); PopupMenu lookAndFeels; - lookAndFeels.addItem (201, T("Default"), true, (typeid (LookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel())) != 0); - lookAndFeels.addItem (200, T("Old School"), true, (typeid (OldSchoolLookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel())) != 0); + lookAndFeels.addItem (201, "Default", true, (typeid (LookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel())) != 0); + lookAndFeels.addItem (200, "Old School", true, (typeid (OldSchoolLookAndFeel) == typeid (LookAndFeel::getDefaultLookAndFeel())) != 0); menu.addSeparator(); - menu.addSubMenu (T("Look and Feel"), lookAndFeels); + menu.addSubMenu ("Look and Feel", lookAndFeels); menu.addSeparator(); menu.addCommandItem (commandManager, CommandIDs::showGrid); @@ -325,9 +325,9 @@ const PopupMenu MainWindow::getMenuForIndex (int topLevelMenuIndex, PopupMenu m; for (int i = 0; i < numElementsInArray (snapSizes); ++i) - m.addItem (300 + i, String (snapSizes[i]) + T(" pixels"), true, snapSizes[i] == currentSnapSize); + m.addItem (300 + i, String (snapSizes[i]) + " pixels", true, snapSizes[i] == currentSnapSize); - menu.addSubMenu (T("Grid size"), m, getActiveDocument() != 0); + menu.addSubMenu ("Grid size", m, getActiveDocument() != 0); menu.addSeparator(); menu.addCommandItem (commandManager, CommandIDs::zoomIn); @@ -340,7 +340,7 @@ const PopupMenu MainWindow::getMenuForIndex (int topLevelMenuIndex, overlays.addCommandItem (commandManager, CommandIDs::compOverlay33); overlays.addCommandItem (commandManager, CommandIDs::compOverlay66); overlays.addCommandItem (commandManager, CommandIDs::compOverlay100); - menu.addSubMenu (T("Component Overlay"), overlays, + menu.addSubMenu ("Component Overlay", overlays, getActiveDocument() != 0 && getActiveDocument()->getComponentLayout() != 0); menu.addSeparator(); @@ -409,8 +409,8 @@ void MainWindow::getCommandInfo (const CommandID commandID, ApplicationCommandIn { const int index = commandID - CommandIDs::newDocumentBase; - result.setInfo (T("New ") + String (ObjectTypes::documentTypeNames [index]), - T("Creates a new ") + String (ObjectTypes::documentTypeNames[index]), + result.setInfo ("New " + String (ObjectTypes::documentTypeNames [index]), + "Creates a new " + String (ObjectTypes::documentTypeNames[index]), CommandCategories::general, 0); return; @@ -421,22 +421,22 @@ void MainWindow::getCommandInfo (const CommandID commandID, ApplicationCommandIn switch (commandID) { case CommandIDs::open: - result.setInfo (T("Open..."), - T("Opens a Jucer .cpp component file for editing."), + result.setInfo ("Open...", + "Opens a Jucer .cpp component file for editing.", CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress (T('o'), cmd, 0)); + result.defaultKeypresses.add (KeyPress ('o', cmd, 0)); break; case CommandIDs::showPrefs: - result.setInfo (T("Preferences..."), - T("Shows the preferences panel."), + result.setInfo ("Preferences...", + "Shows the preferences panel.", CommandCategories::general, 0); - result.defaultKeypresses.add (KeyPress (T(','), cmd, 0)); + result.defaultKeypresses.add (KeyPress (',', cmd, 0)); break; case CommandIDs::useTabbedWindows: - result.setInfo (T("Use tabs to show windows"), - T("Flips between a tabbed component and separate windows"), + result.setInfo ("Use tabs to show windows", + "Flips between a tabbed component and separate windows", CommandCategories::general, 0); result.setTicked (multiDocHolder->getLayoutMode() == MultiDocumentPanel::MaximisedWindowsWithTabs); break; diff --git a/extras/the jucer/src/ui/jucer_PaintRoutinePanel.cpp b/extras/the jucer/src/ui/jucer_PaintRoutinePanel.cpp index 86d592bbd7..a4e5468a11 100644 --- a/extras/the jucer/src/ui/jucer_PaintRoutinePanel.cpp +++ b/extras/the jucer/src/ui/jucer_PaintRoutinePanel.cpp @@ -36,7 +36,7 @@ class ComponentBackgroundColourProperty : public ColourPropertyComponent, public: ComponentBackgroundColourProperty (JucerDocument& document_, PaintRoutine& routine_) - : ColourPropertyComponent (T("background"), false), + : ColourPropertyComponent ("background", false), document (document_), routine (routine_) { @@ -120,7 +120,7 @@ public: Array props; props.add (new ComponentBackgroundColourProperty (*document, paintRoutine)); - propsPanel->addSection (T("Class Properties"), props); + propsPanel->addSection ("Class Properties", props); } if (state != 0) @@ -151,7 +151,7 @@ public: Array props; point->getEditableProperties (props); - propsPanel->addSection (T("Path segment"), props); + propsPanel->addSection ("Path segment", props); } } } diff --git a/extras/the jucer/src/ui/jucer_PrefsPanel.cpp b/extras/the jucer/src/ui/jucer_PrefsPanel.cpp index d12bc1973e..dd5bfd13f1 100644 --- a/extras/the jucer/src/ui/jucer_PrefsPanel.cpp +++ b/extras/the jucer/src/ui/jucer_PrefsPanel.cpp @@ -115,9 +115,9 @@ public: //============================================================================== -static const tchar* miscPage = T("Misc"); -static const tchar* keysPage = T("Keys"); -static const tchar* aboutPage = T("About"); +static const char* miscPage = "Misc"; +static const char* keysPage = "Keys"; +static const char* aboutPage = "About"; class PrefsTabComp : public PreferencesPanel { diff --git a/extras/the jucer/src/ui/jucer_ResourceEditorPanel.cpp b/extras/the jucer/src/ui/jucer_ResourceEditorPanel.cpp index 619b14e853..f7c0d9abe1 100644 --- a/extras/the jucer/src/ui/jucer_ResourceEditorPanel.cpp +++ b/extras/the jucer/src/ui/jucer_ResourceEditorPanel.cpp @@ -84,21 +84,21 @@ private: ResourceEditorPanel::ResourceEditorPanel (JucerDocument& document_) : document (document_) { - addAndMakeVisible (addButton = new TextButton (T("Add new resource..."))); + addAndMakeVisible (addButton = new TextButton ("Add new resource...")); addButton->addListener (this); - addAndMakeVisible (reloadAllButton = new TextButton (T("Reload all resources"))); + addAndMakeVisible (reloadAllButton = new TextButton ("Reload all resources")); reloadAllButton->addListener (this); - addAndMakeVisible (delButton = new TextButton (T("Delete selected resources"))); + addAndMakeVisible (delButton = new TextButton ("Delete selected resources")); delButton->addListener (this); delButton->setEnabled (false); addAndMakeVisible (listBox = new TableListBox (String::empty, this)); - listBox->getHeader().addColumn (T("name"), 1, 150, 80, 400); - listBox->getHeader().addColumn (T("original file"), 2, 350, 80, 800); - listBox->getHeader().addColumn (T("size"), 3, 100, 40, 150); - listBox->getHeader().addColumn (T("reload"), 4, 100, 100, 100, TableHeaderComponent::notResizableOrSortable); + listBox->getHeader().addColumn ("name", 1, 150, 80, 400); + listBox->getHeader().addColumn ("original file", 2, 350, 80, 800); + listBox->getHeader().addColumn ("size", 3, 100, 40, 150); + listBox->getHeader().addColumn ("reload", 4, 100, 100, 100, TableHeaderComponent::notResizableOrSortable); listBox->getHeader().setStretchToFitActive (true); listBox->setColour (ListBox::outlineColourId, Colours::darkgrey); @@ -256,8 +256,8 @@ void ResourceEditorPanel::buttonClicked (Button* b) if (b == addButton) { document.getResources() - .browseForResource (T("Select a file to add as a resource"), - T("*"), + .browseForResource ("Select a file to add as a resource", + "*", File::nonexistent, String::empty); } diff --git a/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp b/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp index 11ca6bd858..bc15a08316 100644 --- a/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp +++ b/extras/the jucer/src/utility/jucer_UtilityFunctions.cpp @@ -38,39 +38,39 @@ const String replaceCEscapeChars (const String& s) for (int i = 0; i < len; ++i) { - const tchar c = s[i]; + const juce_wchar c = s[i]; switch (c) { case '\t': - r << T("\\t"); + r << "\\t"; lastWasHexEscapeCode = false; break; case '\r': - r << T("\\r"); + r << "\\r"; lastWasHexEscapeCode = false; break; case '\n': - r << T("\\n"); + r << "\\n"; lastWasHexEscapeCode = false; break; case '\\': - r << T("\\\\"); + r << "\\\\"; lastWasHexEscapeCode = false; break; case '\'': - r << T("\\\'"); + r << "\\\'"; lastWasHexEscapeCode = false; break; case '\"': - r << T("\\\""); + r << "\\\""; lastWasHexEscapeCode = false; break; default: if (c < 128 && ! (lastWasHexEscapeCode - && String (T("0123456789abcdefABCDEF")).containsChar (c))) // (have to avoid following a hex escape sequence with a valid hex digit) + && String ("0123456789abcdefABCDEF").containsChar (c))) // (have to avoid following a hex escape sequence with a valid hex digit) { r << c; lastWasHexEscapeCode = false; @@ -78,7 +78,7 @@ const String replaceCEscapeChars (const String& s) else { lastWasHexEscapeCode = true; - r << T("\\x") << String::toHexString ((int) c); + r << "\\x" << String::toHexString ((int) c); } break; @@ -91,9 +91,9 @@ const String replaceCEscapeChars (const String& s) const String quotedString (const String& s) { if (s.isEmpty()) - return T("String::empty"); + return "String::empty"; - const int embeddedIndex = s.indexOfIgnoreCase (T("%%")); + const int embeddedIndex = s.indexOfIgnoreCase ("%%"); if (embeddedIndex >= 0) { @@ -101,7 +101,7 @@ const String quotedString (const String& s) String s2 (s.substring (embeddedIndex + 2)); String code; - const int closeIndex = s2.indexOf (T("%%")); + const int closeIndex = s2.indexOf ("%%"); if (closeIndex > 0) { @@ -114,41 +114,41 @@ const String quotedString (const String& s) String result; if (s1.isNotEmpty()) - result << quotedString (s1) << T(" + "); + result << quotedString (s1) << " + "; result << code; if (s2.isNotEmpty()) - result << T(" + ") << quotedString (s2); + result << " + " << quotedString (s2); return result; } } - return T("T(\"") + replaceCEscapeChars (s) + T("\")"); + return "T(\"" + replaceCEscapeChars (s) + "\")"; } const String replaceStringTranslations (String s, JucerDocument* document) { - s = s.replace (T("%%getName()%%"), document->getComponentName()); - s = s.replace (T("%%getButtonText()%%"), document->getComponentName()); + s = s.replace ("%%getName()%%", document->getComponentName()); + s = s.replace ("%%getButtonText()%%", document->getComponentName()); return s; } const String castToFloat (const String& expression) { - if (expression.containsOnly (T("0123456789.f"))) + if (expression.containsOnly ("0123456789.f")) { String s (expression.getFloatValue()); - if (s.containsChar (T('.'))) - return s + T("f"); + if (s.containsChar ('.')) + return s + "f"; - return s + T(".0f"); + return s + ".0f"; } - return T("(float) (") + expression + T(")"); + return "(float) (" + expression + ")"; } const String indentCode (const String& code, const int numSpaces) @@ -156,7 +156,7 @@ const String indentCode (const String& code, const int numSpaces) if (numSpaces == 0) return code; - const String space (String::repeatedString (T(" "), numSpaces)); + const String space (String::repeatedString (" ", numSpaces)); StringArray lines; lines.addLines (code); @@ -170,7 +170,7 @@ const String indentCode (const String& code, const int numSpaces) lines.set (i, s); } - return lines.joinIntoString (T("\n")); + return lines.joinIntoString ("\n"); } //============================================================================== @@ -180,9 +180,9 @@ const String makeValidCppIdentifier (String s, const bool allowTemplates) { if (removeColons) - s = s.replaceCharacters (T(".,;:/@"), T("______")); + s = s.replaceCharacters (".,;:/@", "______"); else - s = s.replaceCharacters (T(".,;/@"), T("_____")); + s = s.replaceCharacters (".,;/@", "_____"); int i; for (i = s.length(); --i > 0;) @@ -192,12 +192,12 @@ const String makeValidCppIdentifier (String s, && ! CharacterFunctions::isUpperCase (s[i - 1])) s = s.substring (0, i) + T(" ") + s.substring (i); - String allowedChars (T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ 0123456789")); + String allowedChars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ 0123456789"); if (allowTemplates) - allowedChars += T("<>"); + allowedChars += "<>"; if (! removeColons) - allowedChars += T(":"); + allowedChars += ":"; StringArray words; words.addTokens (s.retainCharacters (allowedChars), false); @@ -221,21 +221,21 @@ const String makeValidCppIdentifier (String s, n = T("_") + n; // make sure it's not a reserved c++ keyword.. - static const tchar* const reservedWords[] = + static const char* const reservedWords[] = { - T("auto"), T("const"), T("double"), T("float"), T("int"), T("short"), T("struct"), - T("return"), T("static"), T("union"), T("while"), T("asm"), T("dynamic_cast"), - T("unsigned"), T("break"), T("continue"), T("else"), T("for"), T("long"), T("signed"), - T("switch"), T("void"), T("case"), T("default"), T("enum"), T("goto"), T("register"), - T("sizeof"), T("typedef"), T("volatile"), T("char"), T("do"), T("extern"), T("if"), - T("namespace"), T("reinterpret_cast"), T("try"), T("bool"), T("explicit"), T("new"), - T("static_cast"), T("typeid"), T("catch"), T("false"), T("operator"), T("template"), - T("typename"), T("class"), T("friend"), T("private"), T("this"), T("using"), T("const_cast"), - T("inline"), T("public"), T("throw"), T("virtual"), T("delete"), T("mutable"), T("protected"), - T("true"), T("wchar_t"), T("and"), T("bitand"), T("compl"), T("not_eq"), T("or_eq"), - T("xor_eq"), T("and_eq"), T("bitor"), T("not"), T("or"), T("xor"), T("cin"), T("endl"), - T("INT_MIN"), T("iomanip"), T("main"), T("npos"), T("std"), T("cout"), T("include"), - T("INT_MAX"), T("iostream"), T("MAX_RAND"), T("NULL"), T("string") + "auto", "const", "double", "float", "int", "short", "struct", + "return", "static", "union", "while", "asm", "dynamic_cast", + "unsigned", "break", "continue", "else", "for", "long", "signed", + "switch", "void", "case", "default", "enum", "goto", "register", + "sizeof", "typedef", "volatile", "char", "do", "extern", "if", + "namespace", "reinterpret_cast", "try", "bool", "explicit", "new", + "static_cast", "typeid", "catch", "false", "operator", "template", + "typename", "class", "friend", "private", "this", "using", "const_cast", + "inline", "public", "throw", "virtual", "delete", "mutable", "protected", + "true", "wchar_t", "and", "bitand", "compl", "not_eq", "or_eq", + "xor_eq", "and_eq", "bitor", "not", "or", "xor", "cin", "endl", + "INT_MIN", "iomanip", "main", "npos", "std", "cout", "include", + "INT_MAX", "iostream", "MAX_RAND", "NULL", "string" }; for (i = 0; i < numElementsInArray (reservedWords); ++i) @@ -266,7 +266,7 @@ const String valueToFloat (const double v) { String s ((double) (float) v, 4); - if (s.containsChar (T('.'))) + if (s.containsChar ('.')) s << 'f'; else s << ".0f"; @@ -276,7 +276,7 @@ const String valueToFloat (const double v) const String boolToString (const bool b) { - return b ? T("true") : T("false"); + return b ? "true" : "false"; } //============================================================================== @@ -307,17 +307,17 @@ const String colourToCode (const Colour& col) for (int i = 0; i < numElementsInArray (colourNames) - 1; ++i) if (col == colours[i]) - return T("Colours::") + String (colourNames[i]); + return "Colours::" + String (colourNames[i]); - return T("Colour (0x") + colourToHex (col) + T(')'); + return "Colour (0x" + colourToHex (col) + ")"; } -void setColourXml (XmlElement& xml, const tchar* const attName, const Colour& colour) +void setColourXml (XmlElement& xml, const char* const attName, const Colour& colour) { xml.setAttribute (attName, colourToHex (colour)); } -const Colour getColourXml (const XmlElement& xml, const tchar* const attName, const Colour& defaultColour) +const Colour getColourXml (const XmlElement& xml, const char* const attName, const Colour& defaultColour) { return Colour (xml.getStringAttribute (attName, colourToHex (defaultColour)).getHexValue32()); } @@ -563,7 +563,7 @@ const String justificationToCode (const Justification& justification) break; } - return T("Justification (") + String (justification.getFlags()) + T(")"); + return "Justification (" + String (justification.getFlags()) + ")"; } //============================================================================== @@ -737,24 +737,24 @@ void RelativePositionedRectangle::updateFrom (double newX, double newY, double n void RelativePositionedRectangle::applyToXml (XmlElement& e) const { - e.setAttribute (T("pos"), rect.toString()); + e.setAttribute ("pos", rect.toString()); if (relativeToX != 0) - e.setAttribute (T("posRelativeX"), String::toHexString (relativeToX)); + e.setAttribute ("posRelativeX", String::toHexString (relativeToX)); if (relativeToY != 0) - e.setAttribute (T("posRelativeY"), String::toHexString (relativeToY)); + e.setAttribute ("posRelativeY", String::toHexString (relativeToY)); if (relativeToW != 0) - e.setAttribute (T("posRelativeW"), String::toHexString (relativeToW)); + e.setAttribute ("posRelativeW", String::toHexString (relativeToW)); if (relativeToH != 0) - e.setAttribute (T("posRelativeH"), String::toHexString (relativeToH)); + e.setAttribute ("posRelativeH", String::toHexString (relativeToH)); } void RelativePositionedRectangle::restoreFromXml (const XmlElement& e, const RelativePositionedRectangle& defaultPos) { - rect = PositionedRectangle (e.getStringAttribute (T("pos"), defaultPos.rect.toString())); - relativeToX = e.getStringAttribute (T("posRelativeX"), String::toHexString (defaultPos.relativeToX)).getHexValue64(); - relativeToY = e.getStringAttribute (T("posRelativeY"), String::toHexString (defaultPos.relativeToY)).getHexValue64(); - relativeToW = e.getStringAttribute (T("posRelativeW"), String::toHexString (defaultPos.relativeToW)).getHexValue64(); - relativeToH = e.getStringAttribute (T("posRelativeH"), String::toHexString (defaultPos.relativeToH)).getHexValue64(); + rect = PositionedRectangle (e.getStringAttribute ("pos", defaultPos.rect.toString())); + relativeToX = e.getStringAttribute ("posRelativeX", String::toHexString (defaultPos.relativeToX)).getHexValue64(); + relativeToY = e.getStringAttribute ("posRelativeY", String::toHexString (defaultPos.relativeToY)).getHexValue64(); + relativeToW = e.getStringAttribute ("posRelativeW", String::toHexString (defaultPos.relativeToW)).getHexValue64(); + relativeToH = e.getStringAttribute ("posRelativeH", String::toHexString (defaultPos.relativeToH)).getHexValue64(); } diff --git a/extras/the jucer/src/utility/jucer_UtilityFunctions.h b/extras/the jucer/src/utility/jucer_UtilityFunctions.h index e5ca42084b..8ceb9e73e6 100644 --- a/extras/the jucer/src/utility/jucer_UtilityFunctions.h +++ b/extras/the jucer/src/utility/jucer_UtilityFunctions.h @@ -637,8 +637,8 @@ int indexOfLineStartingWith (const StringArray& lines, const String& text, int s const String colourToHex (const Colour& col); const String colourToCode (const Colour& col); -void setColourXml (XmlElement& xml, const tchar* const attName, const Colour& colour); -const Colour getColourXml (const XmlElement& xml, const tchar* const attName, const Colour& defaultColour); +void setColourXml (XmlElement& xml, const char* const attName, const Colour& colour); +const Colour getColourXml (const XmlElement& xml, const char* const attName, const Colour& defaultColour); //============================================================================== const String positionToString (const RelativePositionedRectangle& pos); diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 95701be110..27e13aef67 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -9863,7 +9863,7 @@ const String URL::removeEscapeChars (const String& s) // We need to operate on the string as raw UTF8 chars, and then recombine them into unicode // after all the replacements have been made, so that multi-byte chars are handled. - Array utf8 (result.toUTF8(), result.getNumBytesAsUTF8()); + Array utf8 (result.toUTF8().getAddress(), result.getNumBytesAsUTF8()); for (int i = 0; i < utf8.size(); ++i) { @@ -9888,7 +9888,7 @@ const String URL::addEscapeChars (const String& s, const bool isParameter) const CharPointer_UTF8 legalChars (isParameter ? "_-.*!'()" : ",$_-.*!'()"); - Array utf8 (s.toUTF8(), s.getNumBytesAsUTF8()); + Array utf8 (s.toUTF8().getAddress(), s.getNumBytesAsUTF8()); for (int i = 0; i < utf8.size(); ++i) { @@ -11093,18 +11093,18 @@ BEGIN_JUCE_NAMESPACE juce_wchar CharacterFunctions::toUpperCase (const juce_wchar character) throw() { - return towupper (character); + return towupper ((wchar_t) character); } juce_wchar CharacterFunctions::toLowerCase (const juce_wchar character) throw() { - return towlower (character); + return towlower ((wchar_t) character); } bool CharacterFunctions::isUpperCase (const juce_wchar character) throw() { #if JUCE_WINDOWS - return iswupper (character) != 0; + return iswupper ((wchar_t) character) != 0; #else return toLowerCase (character) != character; #endif @@ -11113,7 +11113,7 @@ bool CharacterFunctions::isUpperCase (const juce_wchar character) throw() bool CharacterFunctions::isLowerCase (const juce_wchar character) throw() { #if JUCE_WINDOWS - return iswlower (character) != 0; + return iswlower ((wchar_t) character) != 0; #else return toUpperCase (character) != character; #endif @@ -11126,7 +11126,7 @@ bool CharacterFunctions::isWhitespace (const char character) throw() bool CharacterFunctions::isWhitespace (const juce_wchar character) throw() { - return iswspace (character) != 0; + return iswspace ((wchar_t) character) != 0; } bool CharacterFunctions::isDigit (const char character) throw() @@ -11136,7 +11136,7 @@ bool CharacterFunctions::isDigit (const char character) throw() bool CharacterFunctions::isDigit (const juce_wchar character) throw() { - return iswdigit (character) != 0; + return iswdigit ((wchar_t) character) != 0; } bool CharacterFunctions::isLetter (const char character) throw() @@ -11147,7 +11147,7 @@ bool CharacterFunctions::isLetter (const char character) throw() bool CharacterFunctions::isLetter (const juce_wchar character) throw() { - return iswalpha (character) != 0; + return iswalpha ((wchar_t) character) != 0; } bool CharacterFunctions::isLetterOrDigit (const char character) throw() @@ -11159,7 +11159,7 @@ bool CharacterFunctions::isLetterOrDigit (const char character) throw() bool CharacterFunctions::isLetterOrDigit (const juce_wchar character) throw() { - return iswalnum (character) != 0; + return iswalnum ((wchar_t) character) != 0; } int CharacterFunctions::getHexDigitValue (const juce_wchar digit) throw() @@ -11186,11 +11186,11 @@ int CharacterFunctions::ftime (char* const dest, const int maxChars, const char* int CharacterFunctions::ftime (juce_wchar* const dest, const int maxChars, const juce_wchar* const format, const struct tm* const tm) throw() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 HeapBlock tempDest; tempDest.calloc (maxChars + 2); int result = ftime (tempDest.getData(), maxChars, String (format).toUTF8(), tm); - CharPointer_UTF32 (dest).copyAndAdvance (CharPointer_UTF8 (tempDest.getData())); + CharPointer_UTF32 (dest).writeAll (CharPointer_UTF8 (tempDest.getData())); return result; #else return (int) wcsftime (dest, maxChars, format, tm); @@ -11389,35 +11389,63 @@ public: text[0] = 0; } - static juce_wchar* createUninitialised (const size_t numChars) + typedef String::CharPointerType CharPointerType; + + static const CharPointerType createUninitialised (const size_t numChars) { StringHolder* const s = reinterpret_cast (new char [sizeof (StringHolder) + numChars * sizeof (juce_wchar)]); s->refCount.value = 0; s->allocatedNumChars = numChars; - return &(s->text[0]); + return CharPointerType (&(s->text[0])); } - static juce_wchar* createCopy (const juce_wchar* const src, const size_t numChars) + template + static const CharPointerType createFromCharPointer (const CharPointer& text) { - juce_wchar* const dest = createUninitialised (numChars); - copyChars (dest, src, numChars); + if (text.getAddress() == 0 || text.isEmpty()) + return getEmpty(); + + const size_t numChars = text.length(); + const CharPointerType dest (createUninitialised (numChars)); + CharPointerType (dest).writeAll (text); return dest; } - static juce_wchar* createCopy (const char* const src, const size_t numChars) + template + static const CharPointerType createFromCharPointer (const CharPointer& text, size_t maxChars) { - juce_wchar* const dest = createUninitialised (numChars); - CharPointer_UTF32 (dest).copyAndAdvanceUpToNumChars (CharPointer_UTF8 (src), numChars); - dest [numChars] = 0; + if (text.getAddress() == 0 || text.isEmpty()) + return getEmpty(); + + size_t numChars = text.lengthUpTo (maxChars); + if (numChars == 0) + return getEmpty(); + + const CharPointerType dest (createUninitialised (numChars)); + CharPointerType (dest).writeWithCharLimit (text, (int) (numChars + 1)); return dest; } - static inline juce_wchar* getEmpty() throw() + static CharPointerType createFromFixedLength (const juce_wchar* const src, const size_t numChars) { - return &(empty.text[0]); + CharPointerType dest (createUninitialised (numChars)); + copyChars (dest, CharPointerType (src), (int) numChars); + return dest; } - static void retain (juce_wchar* const text) throw() + static const CharPointerType createFromFixedLength (const char* const src, const size_t numChars) + { + const CharPointerType dest (createUninitialised (numChars)); + CharPointerType (dest).writeWithCharLimit (CharPointer_UTF8 (src), (int) (numChars + 1)); + return dest; + } + + static inline const CharPointerType getEmpty() throw() + { + return CharPointerType (&(empty.text[0])); + } + + static void retain (const CharPointerType& text) throw() { ++(bufferFromText (text)->refCount); } @@ -11428,48 +11456,48 @@ public: delete[] reinterpret_cast (b); } - static void release (juce_wchar* const text) throw() + static void release (const CharPointerType& text) throw() { release (bufferFromText (text)); } - static juce_wchar* makeUnique (juce_wchar* const text) + static CharPointerType makeUnique (const CharPointerType& text) { StringHolder* const b = bufferFromText (text); if (b->refCount.get() <= 0) return text; - juce_wchar* const newText = createCopy (text, b->allocatedNumChars); + CharPointerType newText (createFromFixedLength (text, b->allocatedNumChars)); release (b); return newText; } - static juce_wchar* makeUniqueWithSize (juce_wchar* const text, size_t numChars) + static CharPointerType makeUniqueWithSize (const CharPointerType& text, size_t numChars) { StringHolder* const b = bufferFromText (text); if (b->refCount.get() <= 0 && b->allocatedNumChars >= numChars) return text; - juce_wchar* const newText = createUninitialised (jmax (b->allocatedNumChars, numChars)); + CharPointerType newText (createUninitialised (jmax (b->allocatedNumChars, numChars))); copyChars (newText, text, b->allocatedNumChars); release (b); return newText; } - static size_t getAllocatedNumChars (juce_wchar* const text) throw() + static size_t getAllocatedNumChars (const CharPointerType& text) throw() { return bufferFromText (text)->allocatedNumChars; } - static void copyChars (juce_wchar* const dest, const juce_wchar* const src, const size_t numChars) throw() + static void copyChars (CharPointerType dest, const CharPointerType& src, const size_t numChars) throw() { - jassert (src != 0 && dest != 0); - memcpy (dest, src, numChars * sizeof (juce_wchar)); - dest [numChars] = 0; + jassert (src.getAddress() != 0 && dest.getAddress() != 0); + memcpy (dest.getAddress(), src.getAddress(), numChars * sizeof (juce_wchar)); + CharPointerType (dest + (int) numChars).writeNull(); } Atomic refCount; @@ -11479,10 +11507,10 @@ public: static StringHolder empty; private: - static inline StringHolder* bufferFromText (void* const text) throw() + static inline StringHolder* bufferFromText (const CharPointerType& text) throw() { // (Can't use offsetof() here because of warnings about this not being a POD) - return reinterpret_cast (static_cast (text) + return reinterpret_cast (reinterpret_cast (text.getAddress()) - (reinterpret_cast (reinterpret_cast (1)->text) - 1)); } }; @@ -11490,14 +11518,7 @@ private: StringHolder StringHolder::empty; const String String::empty; -void String::createInternal (const juce_wchar* const t, const size_t numChars) -{ - jassert (t[numChars] == 0); // must have a null terminator - - text = StringHolder::createCopy (t, numChars); -} - -void String::appendInternal (const juce_wchar* const newText, const int numExtraChars) +void String::appendFixedLength (const juce_wchar* const newText, const int numExtraChars) { if (numExtraChars > 0) { @@ -11505,7 +11526,7 @@ void String::appendInternal (const juce_wchar* const newText, const int numExtra const int newTotalLen = oldLen + numExtraChars; text = StringHolder::makeUniqueWithSize (text, newTotalLen); - StringHolder::copyChars (text + oldLen, newText, numExtraChars); + StringHolder::copyChars (text + oldLen, CharPointer_UTF32 (newText), numExtraChars); } } @@ -11537,9 +11558,8 @@ void String::swapWith (String& other) throw() String& String::operator= (const String& other) throw() { - juce_wchar* const newText = other.text; - StringHolder::retain (newText); - StringHolder::release (reinterpret_cast &> (text).exchange (newText)); + StringHolder::retain (other.text); + StringHolder::release (text.atomicSwap (other.text)); return *this; } @@ -11551,6 +11571,7 @@ String::String (const Preallocation& preallocationSize) } String::String (const String& stringToCopy, const size_t charsToAllocate) + : text (0) { const size_t otherSize = StringHolder::getAllocatedNumChars (stringToCopy.text); text = StringHolder::createUninitialised (jmax (charsToAllocate, otherSize)); @@ -11558,45 +11579,55 @@ String::String (const String& stringToCopy, const size_t charsToAllocate) } String::String (const char* const t) + : text (StringHolder::createFromCharPointer (CharPointer_UTF8 (t))) { - if (t != 0 && *t != 0) - text = StringHolder::createCopy (t, CharPointer_UTF8 (t).length()); - else - text = StringHolder::getEmpty(); } String::String (const juce_wchar* const t) + : text (StringHolder::createFromCharPointer (CharPointer_UTF32 (t))) { - if (t != 0 && *t != 0) - text = StringHolder::createCopy (t, CharPointer_UTF32 (t).length()); - else - text = StringHolder::getEmpty(); } -String::String (const char* const t, const size_t maxChars) +String::String (const CharPointer_UTF8& t) + : text (StringHolder::createFromCharPointer (t)) { - int i; - for (i = 0; (size_t) i < maxChars; ++i) - if (t[i] == 0) - break; +} - if (i > 0) - text = StringHolder::createCopy (t, i); - else - text = StringHolder::getEmpty(); +String::String (const CharPointer_UTF16& t) + : text (StringHolder::createFromCharPointer (t)) +{ } -String::String (const juce_wchar* const t, const size_t maxChars) +String::String (const CharPointer_UTF32& t) + : text (StringHolder::createFromCharPointer (t)) { - int i; - for (i = 0; (size_t) i < maxChars; ++i) - if (t[i] == 0) - break; +} - if (i > 0) - text = StringHolder::createCopy (t, i); - else - text = StringHolder::getEmpty(); +String::String (const CharPointer_UTF32& t, const size_t maxChars) + : text (StringHolder::createFromCharPointer (t, maxChars)) +{ +} + +#if JUCE_WINDOWS +String::String (const wchar_t* const t) + : text (StringHolder::createFromCharPointer (CharPointer_UTF16 (t))) +{ +} + +String::String (const wchar_t* const t, size_t maxChars) + : text (StringHolder::createFromCharPointer (CharPointer_UTF16 (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) @@ -11610,7 +11641,7 @@ const String String::charToString (const juce_wchar character) namespace NumberToStringConverters { // pass in a pointer to the END of a buffer.. - juce_wchar* int64ToString (juce_wchar* t, const int64 n) throw() + juce_wchar* numberToString (juce_wchar* t, const int64 n) throw() { *--t = 0; int64 v = (n >= 0) ? n : -n; @@ -11628,7 +11659,7 @@ namespace NumberToStringConverters return t; } - juce_wchar* uint64ToString (juce_wchar* t, int64 v) throw() + juce_wchar* numberToString (juce_wchar* t, uint64 v) throw() { *--t = 0; @@ -11642,10 +11673,10 @@ namespace NumberToStringConverters return t; } - juce_wchar* intToString (juce_wchar* t, const int n) throw() + juce_wchar* numberToString (juce_wchar* t, const int n) throw() { if (n == (int) 0x80000000) // (would cause an overflow) - return int64ToString (t, n); + return numberToString (t, (int64) n); *--t = 0; int v = abs (n); @@ -11663,7 +11694,7 @@ namespace NumberToStringConverters return t; } - juce_wchar* uintToString (juce_wchar* t, unsigned int v) throw() + juce_wchar* numberToString (juce_wchar* t, unsigned int v) throw() { *--t = 0; @@ -11719,75 +11750,69 @@ namespace NumberToStringConverters return buffer; } } + + template + const String::CharPointerType createFromInteger (const IntegerType number) + { + juce_wchar buffer [32]; + juce_wchar* const end = buffer + numElementsInArray (buffer); + juce_wchar* const start = numberToString (end, number); + + return StringHolder::createFromFixedLength (start, end - start - 1); + } + + const String::CharPointerType createFromDouble (const double number, const int numberOfDecimalPlaces) + { + char buffer [48]; + size_t len; + char* const start = doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len); + return StringHolder::createFromFixedLength (start, len); + } } String::String (const int number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::intToString (end, number); - createInternal (start, end - start - 1); } String::String (const unsigned int number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::uintToString (end, number); - createInternal (start, end - start - 1); } String::String (const short number) + : text (NumberToStringConverters::createFromInteger ((int) number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::intToString (end, (int) number); - createInternal (start, end - start - 1); } String::String (const unsigned short number) + : text (NumberToStringConverters::createFromInteger ((unsigned int) number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::uintToString (end, (unsigned int) number); - createInternal (start, end - start - 1); } String::String (const int64 number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [32]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::int64ToString (end, number); - createInternal (start, end - start - 1); } String::String (const uint64 number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [32]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::uint64ToString (end, number); - createInternal (start, end - start - 1); } String::String (const float number, const int numberOfDecimalPlaces) + : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces)) { - char buffer [48]; - size_t len; - char* const start = NumberToStringConverters::doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len); - text = StringHolder::createCopy (start, len); } String::String (const double number, const int numberOfDecimalPlaces) + : text (NumberToStringConverters::createFromDouble (number, numberOfDecimalPlaces)) { - char buffer [48]; - size_t len; - char* const start = NumberToStringConverters::doubleToString (buffer, numElementsInArray (buffer), number, numberOfDecimalPlaces, len); - text = StringHolder::createCopy (start, len); } int String::length() const throw() { - return CharPointer_UTF32 (text).length(); + return (int) text.length(); } int String::hashCode() const throw() @@ -11827,6 +11852,21 @@ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const juce_wchar* return string1.compare (string2) == 0; } +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF8& string2) throw() +{ + return string1.getCharPointer().compare (string2) == 0; +} + +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF16& string2) throw() +{ + return string1.getCharPointer().compare (string2) == 0; +} + +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF32& string2) throw() +{ + return string1.getCharPointer().compare (string2) == 0; +} + JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) throw() { return string1.compare (string2) != 0; @@ -11842,6 +11882,21 @@ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const juce_wchar* return string1.compare (string2) != 0; } +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF8& string2) throw() +{ + return string1.getCharPointer().compare (string2) != 0; +} + +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF16& string2) throw() +{ + return string1.getCharPointer().compare (string2) != 0; +} + +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF32& string2) throw() +{ + return string1.getCharPointer().compare (string2) != 0; +} + JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) throw() { return string1.compare (string2) > 0; @@ -11864,50 +11919,50 @@ JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& str bool String::equalsIgnoreCase (const juce_wchar* t) const throw() { - return t != 0 ? CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF32 (t)) == 0 + return t != 0 ? text.compareIgnoreCase (CharPointer_UTF32 (t)) == 0 : isEmpty(); } bool String::equalsIgnoreCase (const char* t) const throw() { - return t != 0 ? CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF8 (t)) == 0 + return t != 0 ? text.compareIgnoreCase (CharPointer_UTF8 (t)) == 0 : isEmpty(); } bool String::equalsIgnoreCase (const String& other) const throw() { return text == other.text - || CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF32 (other.text)) == 0; + || text.compareIgnoreCase (other.text) == 0; } int String::compare (const String& other) const throw() { - return (text == other.text) ? 0 : CharPointer_UTF32 (text).compare (CharPointer_UTF32 (other.text)); + return (text == other.text) ? 0 : text.compare (other.text); } int String::compare (const char* other) const throw() { - return other == 0 ? isEmpty() : CharPointer_UTF32 (text).compare (CharPointer_UTF8 (other)); + return text.compare (CharPointer_UTF8 (other)); } int String::compare (const juce_wchar* other) const throw() { - return other == 0 ? isEmpty() : CharPointer_UTF32 (text).compare (CharPointer_UTF32 (other)); + return text.compare (CharPointer_UTF32 (other)); } int String::compareIgnoreCase (const String& other) const throw() { - return (text == other.text) ? 0 : CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF32 (other.text)); + return (text == other.text) ? 0 : text.compareIgnoreCase (other.text); } int String::compareLexicographically (const String& other) const throw() { - CharPointer_UTF32 s1 (text); + CharPointerType s1 (text); while (! (s1.isEmpty() || s1.isLetterOrDigit())) ++s1; - CharPointer_UTF32 s2 (other.text); + CharPointerType s2 (other.text); while (! (s2.isEmpty() || s2.isLetterOrDigit())) ++s2; @@ -11915,10 +11970,14 @@ int String::compareLexicographically (const String& other) const throw() return s1.compareIgnoreCase (s2); } +void String::append (const String& textToAppend, size_t maxCharsToTake) +{ + appendCharPointer (textToAppend.text, maxCharsToTake); +} + String& String::operator+= (const juce_wchar* const t) { - if (t != 0) - appendInternal (t, CharPointer_UTF32 (t).length()); + appendCharPointer (CharPointer_UTF32 (t)); return *this; } @@ -11926,45 +11985,42 @@ String& String::operator+= (const juce_wchar* const t) String& String::operator+= (const String& other) { if (isEmpty()) - operator= (other); - else - appendInternal (other.text, other.length()); + return operator= (other); + appendCharPointer (other.text); return *this; } String& String::operator+= (const char ch) { - const juce_wchar asString[] = { (juce_wchar) ch, 0 }; - return operator+= (static_cast (asString)); + return operator+= ((juce_wchar) ch); } String& String::operator+= (const juce_wchar ch) { - const juce_wchar asString[] = { (juce_wchar) ch, 0 }; + const juce_wchar asString[] = { ch, 0 }; return operator+= (static_cast (asString)); } -String& String::operator+= (const int number) +#if JUCE_WINDOWS +String& String::operator+= (wchar_t ch) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::intToString (end, number); - appendInternal (start, (int) (end - start)); - return *this; + return operator+= ((juce_wchar) ch); } -void String::append (const juce_wchar* const other, const int howMany) +String& String::operator+= (const wchar_t* t) { - if (howMany > 0) - { - int i; - for (i = 0; i < howMany; ++i) - if (other[i] == 0) - break; + return operator+= (String (t)); +} +#endif - appendInternal (other, i); - } +String& String::operator+= (const int number) +{ + juce_wchar buffer [16]; + juce_wchar* const end = buffer + numElementsInArray (buffer); + juce_wchar* const start = NumberToStringConverters::numberToString (end, number); + appendFixedLength (start, (int) (end - start)); + return *this; } JUCE_API const String JUCE_CALLTYPE operator+ (const char* const string1, const String& string2) @@ -12014,6 +12070,25 @@ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const juce_wchar return string1 += string2; } +#if JUCE_WINDOWS +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, wchar_t string2) +{ + return string1 += string2; +} + +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const wchar_t* string2) +{ + string1.appendCharPointer (CharPointer_UTF16 (string2)); + return string1; +} + +JUCE_API const String JUCE_CALLTYPE operator+ (const wchar_t* string1, const String& string2) +{ + String s (string1); + return s += string2; +} +#endif + JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const char characterToAppend) { return string1 += characterToAppend; @@ -12105,7 +12180,7 @@ int String::lastIndexOfChar (const juce_wchar character) const throw() int String::indexOf (const String& t) const throw() { - return t.isEmpty() ? 0 : CharPointer_UTF32 (text).indexOf (CharPointer_UTF32 (t.text)); + return t.isEmpty() ? 0 : text.indexOf (t.text); } int String::indexOfChar (const int startIndex, @@ -12135,13 +12210,13 @@ int String::indexOfAnyOf (const String& charactersToLookFor, if (startIndex > 0 && startIndex >= length()) return -1; - CharPointer_UTF32 t (text); + CharPointerType t (text); int i = jmax (0, startIndex); t += i; while (! t.isEmpty()) { - if (CharPointer_UTF32 (charactersToLookFor.text).indexOf (*t, ignoreCase) >= 0) + if (charactersToLookFor.text.indexOf (*t, ignoreCase) >= 0) return i; ++i; @@ -12156,7 +12231,7 @@ int String::indexOf (const int startIndex, const String& other) const throw() if (startIndex > 0 && startIndex >= length()) return -1; - int i = CharPointer_UTF32 (text + jmax (0, startIndex)).indexOf (CharPointer_UTF32 (other.text)); + int i = CharPointerType (text + jmax (0, startIndex)).indexOf (other.text); return i >= 0 ? i + startIndex : -1; } @@ -12169,7 +12244,7 @@ int String::indexOfIgnoreCase (const String& other) const throw() const int end = length() - len; for (int i = 0; i <= end; ++i) - if (CharPointer_UTF32 (text + i).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (CharPointerType (text + i).compareIgnoreCaseUpTo (other.text, len) == 0) return i; return -1; @@ -12183,7 +12258,7 @@ int String::indexOfIgnoreCase (const int startIndex, const String& other) const const int end = length() - len; for (int i = jmax (0, startIndex); i <= end; ++i) - if (CharPointer_UTF32 (text + i).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (CharPointerType (text + i).compareIgnoreCaseUpTo (other.text, len) == 0) return i; } @@ -12199,11 +12274,11 @@ int String::lastIndexOf (const String& other) const throw() if (i >= 0) { - const juce_wchar* n = text + i; + CharPointerType n (text + i); while (i >= 0) { - if (CharPointer_UTF32 (n).compareUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (n.compareUpTo (other.text, len) == 0) return i; --n; @@ -12224,11 +12299,11 @@ int String::lastIndexOfIgnoreCase (const String& other) const throw() if (i >= 0) { - const juce_wchar* n = text + i; + CharPointerType n (text + i); while (i >= 0) { - if (CharPointer_UTF32 (n).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (n.compareIgnoreCaseUpTo (other.text, len) == 0) return i; --n; @@ -12243,7 +12318,7 @@ int String::lastIndexOfIgnoreCase (const String& other) const throw() int String::lastIndexOfAnyOf (const String& charactersToLookFor, const bool ignoreCase) const throw() { for (int i = length(); --i >= 0;) - if (CharPointer_UTF32 (charactersToLookFor.text).indexOf (text[i], ignoreCase) >= 0) + if (charactersToLookFor.text.indexOf (text[i], ignoreCase) >= 0) return i; return -1; @@ -12279,13 +12354,13 @@ int String::indexOfWholeWord (const String& word) const throw() { if (word.isNotEmpty()) { - CharPointer_UTF32 t (text); + CharPointerType t (text); const int wordLen = word.length(); - const int end = t.length() - wordLen; + const int end = (int) t.length() - wordLen; for (int i = 0; i <= end; ++i) { - if (t.compareUpTo (CharPointer_UTF32 (word.text), wordLen) == 0 + if (t.compareUpTo (word.text, wordLen) == 0 && (i == 0 || ! (t - 1).isLetterOrDigit()) && ! (t + wordLen).isLetterOrDigit()) return i; @@ -12301,13 +12376,13 @@ int String::indexOfWholeWordIgnoreCase (const String& word) const throw() { if (word.isNotEmpty()) { - CharPointer_UTF32 t (text); + CharPointerType t (text); const int wordLen = word.length(); - const int end = t.length() - wordLen; + const int end = (int) t.length() - wordLen; for (int i = 0; i <= end; ++i) { - if (t.compareIgnoreCaseUpTo (CharPointer_UTF32 (word.text), wordLen) == 0 + if (t.compareIgnoreCaseUpTo (word.text, wordLen) == 0 && (i == 0 || ! (t + -1).isLetterOrDigit()) && ! (t + wordLen).isLetterOrDigit()) return i; @@ -12331,16 +12406,16 @@ bool String::containsWholeWordIgnoreCase (const String& wordToLookFor) const thr namespace WildCardHelpers { - int indexOfMatch (CharPointer_UTF32 wildcard, - CharPointer_UTF32 test, + int indexOfMatch (const String::CharPointerType& wildcard, + String::CharPointerType test, const bool ignoreCase) throw() { int start = 0; while (! test.isEmpty()) { - CharPointer_UTF32 t (test); - CharPointer_UTF32 w (wildcard); + String::CharPointerType t (test); + String::CharPointerType w (wildcard); for (;;) { @@ -12376,8 +12451,8 @@ namespace WildCardHelpers bool String::matchesWildcard (const String& wildcard, const bool ignoreCase) const throw() { - CharPointer_UTF32 w (wildcard.text); - CharPointer_UTF32 t (text); + CharPointerType w (wildcard.text); + CharPointerType t (text); for (;;) { @@ -12403,10 +12478,12 @@ bool String::matchesWildcard (const String& wildcard, const bool ignoreCase) con const String String::repeatedString (const String& stringToRepeat, int numberOfTimesToRepeat) { + if (numberOfTimesToRepeat <= 0) + return String::empty; + const int len = stringToRepeat.length(); String result (Preallocation (len * numberOfTimesToRepeat + 1)); - juce_wchar* n = result.text; - *n = 0; + CharPointerType n (result.text); while (--numberOfTimesToRepeat >= 0) { @@ -12426,11 +12503,11 @@ const String String::paddedLeft (const juce_wchar padCharacter, int minimumLengt return *this; String result (Preallocation (minimumLength + 1)); - juce_wchar* n = result.text; + CharPointerType n (result.text); minimumLength -= len; while (--minimumLength >= 0) - *n++ = padCharacter; + n.write (padCharacter); StringHolder::copyChars (n, text, len); return result; @@ -12445,13 +12522,13 @@ const String String::paddedRight (const juce_wchar padCharacter, int minimumLeng return *this; String result (*this, (size_t) minimumLength); - juce_wchar* n = result.text + len; + CharPointerType n (result.text + len); minimumLength -= len; while (--minimumLength >= 0) - *n++ = padCharacter; + n.write (padCharacter); - *n = 0; + n.writeNull(); return result; } @@ -12534,12 +12611,12 @@ const String String::replaceCharacter (const juce_wchar charToReplace, const juc return *this; String result (*this, size_t()); - juce_wchar* t = result.text + index; + CharPointerType t (result.text + index); - while (*t != 0) + while (! t.isEmpty()) { if (*t == charToReplace) - *t = charToInsert; + t.replaceChar (charToInsert); ++t; } @@ -12551,18 +12628,18 @@ const String String::replaceCharacters (const String& charactersToReplace, const String& charactersToInsertInstead) const { String result (*this, size_t()); - juce_wchar* t = result.text; + CharPointerType t (result.text); const int len2 = charactersToInsertInstead.length(); // the two strings passed in are supposed to be the same length! jassert (len2 == charactersToReplace.length()); - while (*t != 0) + while (! t.isEmpty()) { const int index = charactersToReplace.indexOfChar (*t); if (isPositiveAndBelow (index, len2)) - *t = charactersToInsertInstead [index]; + t.replaceChar (charactersToInsertInstead [index]); ++t; } @@ -12572,12 +12649,12 @@ const String String::replaceCharacters (const String& charactersToReplace, bool String::startsWith (const String& other) const throw() { - return CharPointer_UTF32 (text).compareUpTo (CharPointer_UTF32 (other.text), other.length()) == 0; + return text.compareUpTo (other.text, other.length()) == 0; } bool String::startsWithIgnoreCase (const String& other) const throw() { - return CharPointer_UTF32 (text).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), other.length()) == 0; + return text.compareIgnoreCaseUpTo (other.text, other.length()) == 0; } bool String::startsWithChar (const juce_wchar character) const throw() @@ -12601,7 +12678,7 @@ bool String::endsWith (const String& other) const throw() const int otherLen = other.length(); return thisLen >= otherLen - && CharPointer_UTF32 (text + thisLen - otherLen).compare (CharPointer_UTF32 (other.text)) == 0; + && CharPointerType (text + thisLen - otherLen).compare (other.text) == 0; } bool String::endsWithIgnoreCase (const String& other) const throw() @@ -12610,15 +12687,15 @@ bool String::endsWithIgnoreCase (const String& other) const throw() const int otherLen = other.length(); return thisLen >= otherLen - && CharPointer_UTF32 (text + thisLen - otherLen).compareIgnoreCase (CharPointer_UTF32 (other.text)) == 0; + && CharPointerType (text + thisLen - otherLen).compareIgnoreCase (other.text) == 0; } const String String::toUpperCase() const { String result (Preallocation (this->length())); - CharPointer_UTF32 dest (result.text); - CharPointer_UTF32 src (text); + CharPointerType dest (result.text); + CharPointerType src (text); for (;;) { @@ -12638,8 +12715,8 @@ const String String::toLowerCase() const { String result (Preallocation (this->length())); - CharPointer_UTF32 dest (result.text); - CharPointer_UTF32 src (text); + CharPointerType dest (result.text); + CharPointerType src (text); for (;;) { @@ -12807,13 +12884,13 @@ const String String::trim() const int start = 0; - while (CharPointer_UTF32 (text + start).isWhitespace()) + while ((text + start).isWhitespace()) ++start; const int len = length(); int end = len - 1; - while ((end >= start) && CharPointer_UTF32 (text + end).isWhitespace()) + while ((end >= start) && (text + end).isWhitespace()) --end; ++end; @@ -12831,12 +12908,12 @@ const String String::trimStart() const if (isEmpty()) return empty; - CharPointer_UTF32 t (text); + CharPointerType t (text); while (t.isWhitespace()) ++t; - if (t.getAddress() == text) + if (t == text) return *this; return String (t.getAddress()); @@ -12847,7 +12924,7 @@ const String String::trimEnd() const if (isEmpty()) return empty; - CharPointer_UTF32 endT (text); + CharPointerType endT (text); endT = endT.findTerminatingNull() - 1; while ((endT.getAddress() >= text) && endT.isWhitespace()) @@ -12858,7 +12935,7 @@ const String String::trimEnd() const const String String::trimCharactersAtStart (const String& charactersToTrim) const { - const juce_wchar* t = text; + CharPointerType t (text); while (charactersToTrim.containsChar (*t)) ++t; @@ -12890,18 +12967,21 @@ const String String::retainCharacters (const String& charactersToRetain) const return empty; String result (Preallocation (StringHolder::getAllocatedNumChars (text))); - juce_wchar* dst = result.text; - const juce_wchar* src = text; + CharPointerType dst (result.text); + CharPointerType src (text); - while (*src != 0) + for (;;) { - if (charactersToRetain.containsChar (*src)) - *dst++ = *src; + const juce_wchar c = src.getAndAdvance(); - ++src; + if (c == 0) + break; + + if (charactersToRetain.containsChar (c)) + dst.write (c); } - *dst = 0; + dst.writeNull(); return result; } @@ -12911,18 +12991,21 @@ const String String::removeCharacters (const String& charactersToRemove) const return empty; String result (Preallocation (StringHolder::getAllocatedNumChars (text))); - juce_wchar* dst = result.text; - const juce_wchar* src = text; + CharPointerType dst (result.text); + CharPointerType src (text); - while (*src != 0) + for (;;) { - if (! charactersToRemove.containsChar (*src)) - *dst++ = *src; + const juce_wchar c = src.getAndAdvance(); - ++src; + if (c == 0) + break; + + if (! charactersToRemove.containsChar (c)) + dst.write (c); } - *dst = 0; + dst.writeNull(); return result; } @@ -12959,7 +13042,7 @@ const String String::initialSectionNotContaining (const String& charactersToStop bool String::containsOnly (const String& chars) const throw() { - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) if (! chars.containsChar (t.getAndAdvance())) @@ -12981,7 +13064,7 @@ bool String::containsAnyOf (const String& chars) const throw() bool String::containsNonWhitespaceChars() const throw() { - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) { @@ -13007,28 +13090,24 @@ const String String::formatted (const juce_wchar* const pf, ... ) for (;;) { -#if JUCE_LINUX && JUCE_64BIT + #if JUCE_LINUX && JUCE_64BIT va_list tempArgs; va_copy (tempArgs, args); - const int num = (int) vswprintf (result.text, bufferSize - 1, pf, tempArgs); + const int num = (int) vswprintf (result.text.getAddress(), bufferSize - 1, pf, tempArgs); va_end (tempArgs); -#elif JUCE_WINDOWS - #if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4996) - #endif - const int num = (int) _vsnwprintf (result.text, bufferSize - 1, pf, args); - #if JUCE_MSVC - #pragma warning (pop) - #endif -#elif JUCE_ANDROID + #elif JUCE_WINDOWS + HeapBlock temp (bufferSize); + const int num = (int) _vsnwprintf (temp.getData(), bufferSize - 1, String (pf).toUTF16(), args); + if (num > 0) + CharPointerType (result.text).writeAll (CharPointer_UTF16 (temp.getData())); + #elif JUCE_ANDROID HeapBlock temp (bufferSize); const int num = (int) vsnprintf (temp.getData(), bufferSize - 1, String (pf).toUTF8(), args); if (num > 0) - CharPointer_UTF32 (result.text).copyAndAdvance (CharPointer_UTF8 (temp.getData())); -#else - const int num = (int) vswprintf (result.text, bufferSize - 1, pf, args); -#endif + CharPointerType (result.text).writeAll (CharPointer_UTF8 (temp.getData())); + #else + const int num = (int) vswprintf (result.text.getAddress(), bufferSize - 1, pf, args); + #endif if (num > 0) return result; @@ -13046,15 +13125,14 @@ const String String::formatted (const juce_wchar* const pf, ... ) int String::getIntValue() const throw() { - return CharPointer_UTF32 (text).getIntValue32(); + return text.getIntValue32(); } int String::getTrailingIntValue() const throw() { int n = 0; int mult = 1; - CharPointer_UTF32 t (text); - t = t.findTerminatingNull(); + CharPointerType t (text.findTerminatingNull()); while ((--t).getAddress() >= text) { @@ -13075,7 +13153,7 @@ int String::getTrailingIntValue() const throw() int64 String::getLargeIntValue() const throw() { - return CharPointer_UTF32 (text).getIntValue64(); + return text.getIntValue64(); } float String::getFloatValue() const throw() @@ -13085,7 +13163,7 @@ float String::getFloatValue() const throw() double String::getDoubleValue() const throw() { - return CharPointer_UTF32 (text).getDoubleValue(); + return text.getDoubleValue(); } static const char* const hexDigits = "0123456789abcdef"; @@ -13142,26 +13220,26 @@ const String String::toHexString (const unsigned char* data, const int size, con String s (Preallocation ((size_t) numChars)); - juce_wchar* d = s.text; + CharPointerType dest (s.text); for (int i = 0; i < size; ++i) { - *d++ = (juce_wchar) hexDigits [(*data) >> 4]; - *d++ = (juce_wchar) hexDigits [(*data) & 0xf]; + dest.write ((juce_wchar) hexDigits [(*data) >> 4]); + dest.write ((juce_wchar) hexDigits [(*data) & 0xf]); ++data; if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1)) - *d++ = ' '; + dest.write ((juce_wchar) ' '); } - *d = 0; + dest.writeNull(); return s; } int String::getHexValue32() const throw() { int result = 0; - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) { @@ -13177,7 +13255,7 @@ int String::getHexValue32() const throw() int64 String::getHexValue64() const throw() { int64 result = 0; - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) { @@ -13202,10 +13280,10 @@ const String String::createStringFromData (const void* const data_, const int si { return charToString ((char) data[0]); } - else if ((data[0] == (uint8) 0xfe && data[1] == (uint8) 0xff) // UTF-16 BOM - || (data[0] == (uint8) 0xff && data[1] == (uint8) 0xfe)) + else if ((data[0] == (uint8) CharPointer_UTF16::byteOrderMarkBE1 && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkBE2) + || (data[0] == (uint8) CharPointer_UTF16::byteOrderMarkLE1 && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkLE1)) { - const bool bigEndian = (data[0] == (uint8) 0xfe); + const bool bigEndian = (data[0] == (uint8) CharPointer_UTF16::byteOrderMarkBE1); const int numChars = size / 2 - 1; String result; @@ -13230,7 +13308,10 @@ const String String::createStringFromData (const void* const data_, const int si } else { - if (size >= 3 && data[0] == (uint8) 0xef && data[1] == (uint8) 0xbb && data[2] == (uint8) 0xbf) // UTF-8 BOM + if (size >= 3 + && data[0] == (uint8) CharPointer_UTF8::byteOrderMark1 + && data[1] == (uint8) CharPointer_UTF8::byteOrderMark2 + && data[2] == (uint8) CharPointer_UTF8::byteOrderMark3) return String::fromUTF8 ((const char*) data + 3, size - 3); return String::fromUTF8 ((const char*) data, size); @@ -13242,109 +13323,88 @@ void* String::createSpaceAtEndOfBuffer (const size_t numExtraBytes) const const int currentLen = length() + 1; String& mutableThis = const_cast (*this); - mutableThis.text = StringHolder::makeUniqueWithSize (mutableThis.text, currentLen + 1 + numExtraBytes / sizeof (juce_wchar)); + mutableThis.preallocateStorage (currentLen + 1 + numExtraBytes / sizeof (juce_wchar)); - return mutableThis.text + currentLen; + return (mutableThis.text + currentLen).getAddress(); } -const char* String::toUTF8() const +const CharPointer_UTF8 String::toUTF8() const { if (isEmpty()) - return reinterpret_cast (text); + return CharPointer_UTF8 (reinterpret_cast (text.getAddress())); - const int utf8BytesNeeded = getNumBytesAsUTF8(); - char* const utf8Area = static_cast (createSpaceAtEndOfBuffer (utf8BytesNeeded)); + const size_t extraBytesNeeded = CharPointer_UTF8::getBytesRequiredFor (text); + CharPointer_UTF8 extraSpace (static_cast (createSpaceAtEndOfBuffer (extraBytesNeeded))); #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..) - *(juce_wchar*) (utf8Area + (utf8BytesNeeded & ~(sizeof (juce_wchar) - 1))) = 0; + *(juce_wchar*) (addBytesToPointer (extraSpace.getAddress(), (extraBytesNeeded & ~(sizeof (juce_wchar) - 1)))) = 0; #endif - copyToUTF8 (utf8Area, std::numeric_limits::max()); - return utf8Area; + CharPointer_UTF8 (extraSpace).writeAll (text); + return extraSpace; } -int String::copyToUTF8 (char* const buffer, const int maxBufferSizeBytes) const throw() +CharPointer_UTF16 String::toUTF16() const { - jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! + if (isEmpty()) + return CharPointer_UTF16 (reinterpret_cast (text.getAddress())); - return CharPointer_UTF8 (buffer).copyAndAdvanceUpToBytes (CharPointer_UTF32 (text), maxBufferSizeBytes); -} + const size_t extraBytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text); + CharPointer_UTF16 extraSpace (static_cast (createSpaceAtEndOfBuffer (extraBytesNeeded))); -int String::getNumBytesAsUTF8() const throw() -{ - return CharPointer_UTF8::getBytesRequiredFor (CharPointer_UTF32 (text)); + #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..) + *(juce_wchar*) (addBytesToPointer (extraSpace.getAddress(), (extraBytesNeeded & ~(sizeof (juce_wchar) - 1)))) = 0; + #endif + + CharPointer_UTF16 (extraSpace).writeAll (text); + return extraSpace; } -const String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) +int String::copyToUTF8 (CharPointer_UTF8::CharType* const buffer, const int maxBufferSizeBytes) const throw() { - if (buffer == 0) - return empty; - - if (bufferSizeBytes < 0) - bufferSizeBytes = std::numeric_limits::max(); - - size_t numBytes; - for (numBytes = 0; numBytes < (size_t) bufferSizeBytes; ++numBytes) - if (buffer [numBytes] == 0) - break; - - String result (Preallocation (numBytes + 1)); - juce_wchar* dest = result.text; + jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! - size_t i = 0; - while (i < numBytes) - { - const char c = buffer [i++]; + if (buffer == 0) + return (int) CharPointer_UTF8::getBytesRequiredFor (text); - if (c < 0) - { - unsigned int mask = 0x7f; - int bit = 0x40; - int numExtraValues = 0; + return CharPointer_UTF8 (buffer).writeWithDestByteLimit (text, maxBufferSizeBytes); +} - while (bit != 0 && (c & bit) != 0) - { - bit >>= 1; - mask >>= 1; - ++numExtraValues; - } +int String::copyToUTF16 (CharPointer_UTF16::CharType* const buffer, int maxBufferSizeBytes) const throw() +{ + jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! - int n = (mask & (unsigned char) c); + if (buffer == 0) + return (int) CharPointer_UTF16::getBytesRequiredFor (text); - while (--numExtraValues >= 0 && i < (size_t) bufferSizeBytes) - { - const char nextByte = buffer[i]; + return CharPointer_UTF16 (buffer).writeWithDestByteLimit (text, maxBufferSizeBytes); +} - if ((nextByte & 0xc0) != 0x80) - { - n = c; // reset to original value if the input is invalid. - break; - } +int String::getNumBytesAsUTF8() const throw() +{ + return (int) CharPointer_UTF8::getBytesRequiredFor (text); +} - n <<= 6; - n |= (nextByte & 0x3f); - ++i; - } +const String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) +{ + if (buffer == 0) + return empty; - *dest++ = (juce_wchar) n; - } - else - { - *dest++ = (juce_wchar) c; - } - } + const int len = (int) (bufferSizeBytes >= 0 ? CharPointer_UTF8 (buffer).lengthUpTo (bufferSizeBytes) + : CharPointer_UTF8 (buffer).length()); - *dest = 0; + String result (Preallocation (len + 1)); + CharPointerType (result.text).writeWithCharLimit (CharPointer_UTF8 (buffer), len + 1); return result; } const char* String::toCString() const { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 return toUTF8(); #else if (isEmpty()) - return reinterpret_cast (text); + return reinterpret_cast (text.getAddress()); const int len = getNumBytesAsCString(); char* const extraSpace = static_cast (createSpaceAtEndOfBuffer (len + 1)); @@ -13356,7 +13416,7 @@ const char* String::toCString() const int String::getNumBytesAsCString() const throw() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 return getNumBytesAsUTF8(); #else return (int) wcstombs (0, text, 0); @@ -13365,7 +13425,7 @@ int String::getNumBytesAsCString() const throw() int String::copyToCString (char* destBuffer, const int maxBufferSizeBytes) const throw() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 return copyToUTF8 (destBuffer, maxBufferSizeBytes); #else const int numBytes = (int) wcstombs (destBuffer, text, maxBufferSizeBytes); @@ -13381,14 +13441,6 @@ int String::copyToCString (char* destBuffer, const int maxBufferSizeBytes) const #pragma warning (pop) #endif -void String::copyToUnicode (juce_wchar* const destBuffer, const int maxCharsToCopy) const throw() -{ - jassert (destBuffer != 0 && maxCharsToCopy >= 0); - - if (destBuffer != 0 && maxCharsToCopy >= 0) - StringHolder::copyChars (destBuffer, text, jmin (maxCharsToCopy, length())); -} - String::Concatenator::Concatenator (String& stringToAppendTo) : result (stringToAppendTo), nextIndex (stringToAppendTo.length()) @@ -13406,7 +13458,7 @@ void String::Concatenator::append (const String& s) if (len > 0) { result.preallocateStorage (nextIndex + len); - s.copyToUnicode (static_cast (result) + nextIndex, len); + CharPointerType (result.text + nextIndex).writeAll (s.text); nextIndex += len; } } @@ -13418,6 +13470,51 @@ class StringTests : public UnitTest public: StringTests() : UnitTest ("String class") {} + template + struct TestUTFConversion + { + static void test (UnitTest& test) + { + String s (createRandomWideCharString()); + + typename CharPointerType::CharType buffer [300]; + + memset (buffer, 0xff, sizeof (buffer)); + CharPointerType (buffer).writeAll (s.toUTF32()); + test.expectEquals (String (CharPointerType (buffer)), s); + + memset (buffer, 0xff, sizeof (buffer)); + CharPointerType (buffer).writeAll (s.toUTF16()); + test.expectEquals (String (CharPointerType (buffer)), s); + + memset (buffer, 0xff, sizeof (buffer)); + CharPointerType (buffer).writeAll (s.toUTF8()); + test.expectEquals (String (CharPointerType (buffer)), s); + } + }; + + static const String createRandomWideCharString() + { + juce_wchar buffer [50]; + zerostruct (buffer); + + for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) + { + if (Random::getSystemRandom().nextBool()) + { + do + { + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); + } + while (buffer[i] >= 0xd800 && buffer[i] <= 0xdfff); // (these code-points are illegal in UTF-16) + } + else + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); + } + + return buffer; + } + void runTest() { { @@ -13642,35 +13739,26 @@ public: } { - beginTest ("UTF8"); + beginTest ("UTF conversions"); - String s ("word word2 word3"); - - { - char buffer [100]; - memset (buffer, 0xff, sizeof (buffer)); - s.copyToUTF8 (buffer, 100); - expectEquals (String::fromUTF8 (buffer, 100), s); - - juce_wchar bufferUnicode [100]; - memset (bufferUnicode, 0xff, sizeof (bufferUnicode)); - s.copyToUnicode (bufferUnicode, 100); - expectEquals (String (bufferUnicode, 100), s); - } + TestUTFConversion ::test (*this); + TestUTFConversion ::test (*this); + TestUTFConversion ::test (*this); + } - { - juce_wchar wideBuffer [50]; - zerostruct (wideBuffer); + { + beginTest ("StringArray"); - for (int i = 0; i < numElementsInArray (wideBuffer) - 1; ++i) - wideBuffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); + StringArray s; + for (int i = 5; --i >= 0;) + s.add (String (i)); - String wide (wideBuffer); - expect (wide == (const juce_wchar*) wideBuffer); - expect (wide.length() == numElementsInArray (wideBuffer) - 1); - expect (String::fromUTF8 (wide.toUTF8()) == wide); - expect (String::fromUTF8 (wide.toUTF8()) == wideBuffer); - } + expectEquals (s.joinIntoString ("-"), String ("4-3-2-1-0")); + s.remove (2); + expectEquals (s.joinIntoString ("--"), String ("4--3--1--0")); + expectEquals (s.joinIntoString (String::empty), String ("4310")); + s.clear(); + expectEquals (s.joinIntoString ("x"), String::empty); } } }; @@ -13967,27 +14055,20 @@ const String StringArray::joinIntoString (const String& separator, int start, in String result; result.preallocateStorage (charsNeeded); - juce_wchar* dest = result; + String::CharPointerType dest (result.getCharPointer()); while (start < last) { const String& s = strings.getReference (start); - const int len = s.length(); - if (len > 0) - { - s.copyToUnicode (dest, len); - dest += len; - } + if (! s.isEmpty()) + dest.writeAll (s.getCharPointer()); if (++start < last && separatorLen > 0) - { - separator.copyToUnicode (dest, separatorLen); - dest += separatorLen; - } + dest.writeAll (separator.getCharPointer()); } - *dest = 0; + dest.writeNull(); return result; } @@ -14430,8 +14511,8 @@ namespace XmlIdentifierChars { static const uint32 legalChars[] = { 0, 0x7ff6000, 0x87fffffe, 0x7fffffe, 0 }; - return (c < numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (1 << (c & 31))) != 0) - : isIdentifierCharSlow (c); + return ((int) c < (int) numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (1 << (c & 31))) != 0) + : isIdentifierCharSlow (c); } /*static void generateIdentifierCharConstants() @@ -32364,7 +32445,10 @@ END_JUCE_NAMESPACE #define STRICT #include #include - #pragma warning (disable : 4312 4355 1899) + #pragma warning (disable : 4312 4355) + #ifdef __INTEL_COMPILER + #pragma warning (disable : 1899) + #endif #elif JUCE_LINUX #include #include @@ -34746,7 +34830,7 @@ VstIntPtr VSTPluginInstance::handleCallback (VstInt32 opcode, VstInt32 index, Vs #if JUCE_MAC return (VstIntPtr) (void*) &module->parentDirFSSpec; #else - return (VstIntPtr) (pointer_sized_uint) module->fullParentDirectoryPathName.toUTF8(); + return (VstIntPtr) (pointer_sized_uint) module->fullParentDirectoryPathName.toUTF8().getAddress(); #endif case audioMasterGetAutomationState: @@ -46517,7 +46601,7 @@ namespace CppTokeniser int i = 0; while (k[i] != 0) { - if (k[i][0] == token[0] && CharPointer_UTF8 (k[i]).compare (CharPointer_UTF32 (token)) == 0) + if (k[i][0] == (char) token[0] && CharPointer_UTF8 (k[i]).compare (CharPointer_UTF32 (token)) == 0) return true; ++i; @@ -187349,7 +187433,7 @@ public: vorbis_comment_init (&vc); if (JUCEApplication::getInstance() != 0) - vorbis_comment_add_tag (&vc, "ENCODER", const_cast (JUCEApplication::getInstance()->getApplicationName().toUTF8())); + vorbis_comment_add_tag (&vc, "ENCODER", const_cast (JUCEApplication::getInstance()->getApplicationName().toUTF8().getAddress())); vorbis_analysis_init (&vd, &vi); vorbis_block_init (&vd, &vb); @@ -237178,13 +237262,13 @@ DynamicLibraryLoader::~DynamicLibraryLoader() bool DynamicLibraryLoader::load (const String& name) { FreeLibrary ((HMODULE) libHandle); - libHandle = name.isNotEmpty() ? LoadLibrary (name) : 0; + libHandle = name.isNotEmpty() ? LoadLibrary (name.toUTF16()) : 0; return libHandle != 0; } void* DynamicLibraryLoader::findProcAddress (const String& functionName) { - return (void*) GetProcAddress ((HMODULE) libHandle, functionName.toCString()); // (void* cast is required for mingw) + return (void*) GetProcAddress ((HMODULE) libHandle, functionName.toUTF8()); // (void* cast is required for mingw) } #endif @@ -237199,7 +237283,7 @@ void* DynamicLibraryLoader::findProcAddress (const String& functionName) void Logger::outputDebugString (const String& text) { - OutputDebugString (text + "\n"); + OutputDebugString ((text + "\n").toUTF16()); } static int64 hiResTicksPerSecond; @@ -237803,7 +237887,7 @@ void* PlatformUtilities::loadDynamicLibrary (const String& name) JUCE_TRY { - result = LoadLibrary (name); + result = LoadLibrary (name.toUTF16()); } JUCE_CATCH_ALL @@ -237831,7 +237915,7 @@ public: Pimpl (const String& name, const int timeOutMillisecs) : handle (0), refCount (1) { - handle = CreateMutex (0, TRUE, "Global\\" + name.replaceCharacter ('\\','/')); + handle = CreateMutex (0, TRUE, ("Global\\" + name.replaceCharacter ('\\','/')).toUTF16()); if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS) { @@ -237948,14 +238032,12 @@ namespace WindowsFileHelpers reinterpret_cast (ft)->QuadPart = time * 10000 + literal64bit (116444736000000000); } - const String getDriveFromPath (const String& path) + const String getDriveFromPath (String path) { - const int length = path.length(); - HeapBlock stringCopy (length + 1); - path.copyToUnicode (stringCopy, length); + WCHAR* p = const_cast (path.toUTF16().getAddress()); - if (PathStripToRoot (stringCopy)) - return String (stringCopy); + if (PathStripToRoot (p)) + return String ((const WCHAR*) p); return path; } @@ -237964,7 +238046,7 @@ namespace WindowsFileHelpers { ULARGE_INTEGER spc, tot, totFree; - if (GetDiskFreeSpaceEx (getDriveFromPath (path), &spc, &tot, &totFree)) + if (GetDiskFreeSpaceEx (getDriveFromPath (path).toUTF16(), &spc, &tot, &totFree)) return total ? (int64) tot.QuadPart : (int64) spc.QuadPart; @@ -237973,7 +238055,7 @@ namespace WindowsFileHelpers unsigned int getWindowsDriveType (const String& path) { - return GetDriveType (getDriveFromPath (path)); + return GetDriveType (getDriveFromPath (path).toUTF16()); } const File getSpecialFolderPath (int type) @@ -237993,25 +238075,25 @@ const String File::separatorString ("\\"); bool File::exists() const { return fullPath.isNotEmpty() - && GetFileAttributes (fullPath) != INVALID_FILE_ATTRIBUTES; + && GetFileAttributes (fullPath.toUTF16()) != INVALID_FILE_ATTRIBUTES; } bool File::existsAsFile() const { return fullPath.isNotEmpty() - && (GetFileAttributes (fullPath) & FILE_ATTRIBUTE_DIRECTORY) == 0; + && (GetFileAttributes (fullPath.toUTF16()) & FILE_ATTRIBUTE_DIRECTORY) == 0; } bool File::isDirectory() const { - const DWORD attr = GetFileAttributes (fullPath); + const DWORD attr = GetFileAttributes (fullPath.toUTF16()); return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) && (attr != INVALID_FILE_ATTRIBUTES); } bool File::hasWriteAccess() const { if (exists()) - return (GetFileAttributes (fullPath) & FILE_ATTRIBUTE_READONLY) == 0; + return (GetFileAttributes (fullPath.toUTF16()) & FILE_ATTRIBUTE_READONLY) == 0; // on windows, it seems that even read-only directories can still be written into, // so checking the parent directory's permissions would return the wrong result.. @@ -238020,7 +238102,7 @@ bool File::hasWriteAccess() const bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const { - DWORD attr = GetFileAttributes (fullPath); + DWORD attr = GetFileAttributes (fullPath.toUTF16()); if (attr == INVALID_FILE_ATTRIBUTES) return false; @@ -238033,12 +238115,12 @@ bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const else attr &= ~FILE_ATTRIBUTE_READONLY; - return SetFileAttributes (fullPath, attr) != FALSE; + return SetFileAttributes (fullPath.toUTF16(), attr) != FALSE; } bool File::isHidden() const { - return (GetFileAttributes (getFullPathName()) & FILE_ATTRIBUTE_HIDDEN) != 0; + return (GetFileAttributes (getFullPathName().toUTF16()) & FILE_ATTRIBUTE_HIDDEN) != 0; } bool File::deleteFile() const @@ -238046,9 +238128,9 @@ bool File::deleteFile() const if (! exists()) return true; else if (isDirectory()) - return RemoveDirectory (fullPath) != 0; + return RemoveDirectory (fullPath.toUTF16()) != 0; else - return DeleteFile (fullPath) != 0; + return DeleteFile (fullPath.toUTF16()) != 0; } bool File::moveToTrash() const @@ -238061,7 +238143,7 @@ bool File::moveToTrash() const // The string we pass in must be double null terminated.. String doubleNullTermPath (getFullPathName() + " "); - TCHAR* const p = const_cast (static_cast (doubleNullTermPath)); + WCHAR* const p = const_cast (doubleNullTermPath.toUTF16().getAddress()); p [getFullPathName().length()] = 0; fos.wFunc = FO_DELETE; @@ -238074,17 +238156,17 @@ bool File::moveToTrash() const bool File::copyInternal (const File& dest) const { - return CopyFile (fullPath, dest.getFullPathName(), false) != 0; + return CopyFile (fullPath.toUTF16(), dest.getFullPathName().toUTF16(), false) != 0; } bool File::moveInternal (const File& dest) const { - return MoveFile (fullPath, dest.getFullPathName()) != 0; + return MoveFile (fullPath.toUTF16(), dest.getFullPathName().toUTF16()) != 0; } void File::createDirectoryInternal (const String& fileName) const { - CreateDirectory (fileName, 0); + CreateDirectory (fileName.toUTF16(), 0); } int64 juce_fileSetPosition (void* handle, int64 pos) @@ -238099,7 +238181,7 @@ void FileInputStream::openHandle() { totalSize = file.getSize(); - HANDLE h = CreateFile (file.getFullPathName(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + HANDLE h = CreateFile (file.getFullPathName().toUTF16(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0); if (h != INVALID_HANDLE_VALUE) @@ -238125,7 +238207,7 @@ size_t FileInputStream::readInternal (void* buffer, size_t numBytes) void FileOutputStream::openHandle() { - HANDLE h = CreateFile (file.getFullPathName(), GENERIC_WRITE, FILE_SHARE_READ, 0, + HANDLE h = CreateFile (file.getFullPathName().toUTF16(), GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (h != INVALID_HANDLE_VALUE) @@ -238169,7 +238251,7 @@ int64 File::getSize() const { WIN32_FILE_ATTRIBUTE_DATA attributes; - if (GetFileAttributesEx (fullPath, GetFileExInfoStandard, &attributes)) + if (GetFileAttributesEx (fullPath.toUTF16(), GetFileExInfoStandard, &attributes)) return (((int64) attributes.nFileSizeHigh) << 32) | attributes.nFileSizeLow; return 0; @@ -238180,7 +238262,7 @@ void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int using namespace WindowsFileHelpers; WIN32_FILE_ATTRIBUTE_DATA attributes; - if (GetFileAttributesEx (fullPath, GetFileExInfoStandard, &attributes)) + if (GetFileAttributesEx (fullPath.toUTF16(), GetFileExInfoStandard, &attributes)) { modificationTime = fileTimeToTime (&attributes.ftLastWriteTime); creationTime = fileTimeToTime (&attributes.ftCreationTime); @@ -238197,7 +238279,7 @@ bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 using namespace WindowsFileHelpers; bool ok = false; - HANDLE h = CreateFile (fullPath, GENERIC_WRITE, FILE_SHARE_READ, 0, + HANDLE h = CreateFile (fullPath.toUTF16(), GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (h != INVALID_HANDLE_VALUE) @@ -238245,7 +238327,7 @@ void File::findFileSystemRoots (Array& destArray) const String File::getVolumeLabel() const { TCHAR dest[64]; - if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()), dest, + if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toUTF16(), dest, numElementsInArray (dest), 0, 0, 0, 0, 0)) dest[0] = 0; @@ -238257,7 +238339,7 @@ int File::getVolumeSerialNumber() const TCHAR dest[64]; DWORD serialNum; - if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()), dest, + if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toUTF16(), dest, numElementsInArray (dest), &serialNum, 0, 0, 0, 0)) return 0; @@ -238366,7 +238448,7 @@ const File File::getCurrentWorkingDirectory() bool File::setAsCurrentWorkingDirectory() const { - return SetCurrentDirectory (getFullPathName()) != FALSE; + return SetCurrentDirectory (getFullPathName().toUTF16()) != FALSE; } const String File::getVersion() const @@ -238374,11 +238456,11 @@ const String File::getVersion() const String result; DWORD handle = 0; - DWORD bufferSize = GetFileVersionInfoSize (getFullPathName(), &handle); + DWORD bufferSize = GetFileVersionInfoSize (getFullPathName().toUTF16(), &handle); HeapBlock buffer; buffer.calloc (bufferSize); - if (GetFileVersionInfo (getFullPathName(), 0, bufferSize, buffer)) + if (GetFileVersionInfo (getFullPathName().toUTF16(), 0, bufferSize, buffer)) { VS_FIXEDFILEINFO* vffi; UINT len = 0; @@ -238411,7 +238493,7 @@ const File File::getLinkedTarget() const ComSmartPtr persistFile; if (SUCCEEDED (shellLink.QueryInterface (IID_IPersistFile, persistFile))) { - if (SUCCEEDED (persistFile->Load ((const WCHAR*) p, STGM_READ)) + if (SUCCEEDED (persistFile->Load (p.toUTF16(), STGM_READ)) && SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI))) { WIN32_FIND_DATA winFindData; @@ -238450,7 +238532,7 @@ public: if (handle == INVALID_HANDLE_VALUE) { - handle = FindFirstFile (directoryWithWildCard, &findData); + handle = FindFirstFile (directoryWithWildCard.toUTF16(), &findData); if (handle == INVALID_HANDLE_VALUE) return false; @@ -238502,7 +238584,7 @@ bool PlatformUtilities::openDocument (const String& fileName, const String& para JUCE_TRY { - hInstance = ShellExecute (0, 0, fileName, parameters, 0, SW_SHOWDEFAULT); + hInstance = ShellExecute (0, 0, fileName.toUTF16(), parameters.toUTF16(), 0, SW_SHOWDEFAULT); } JUCE_CATCH_ALL @@ -238528,9 +238610,9 @@ public: { cancelEvent = CreateEvent (0, FALSE, FALSE, 0); - pipeH = isPipe ? CreateNamedPipe (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, + pipeH = isPipe ? CreateNamedPipe (file.toUTF16(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0) - : CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, + : CreateFile (file.toUTF16(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); } @@ -238954,7 +239036,7 @@ private: uc.lpszUrlPath = file; uc.lpszHostName = server; - if (InternetCrackUrl (address, 0, 0, &uc)) + if (InternetCrackUrl (address.toUTF16(), 0, 0, &uc)) { int disable = 1; InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable)); @@ -239014,7 +239096,7 @@ private: INTERNET_BUFFERS buffers; zerostruct (buffers); buffers.dwStructSize = sizeof (INTERNET_BUFFERS); - buffers.lpcszHeader = static_cast (headers); + buffers.lpcszHeader = headers.toUTF16(); buffers.dwHeadersLength = headers.length(); buffers.dwBufferTotal = (DWORD) postData.getSize(); @@ -239242,13 +239324,13 @@ namespace if (createForWriting) { - if (RegCreateKeyEx (rootKey, name, 0, 0, REG_OPTION_NON_VOLATILE, + if (RegCreateKeyEx (rootKey, name.toUTF16(), 0, 0, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS) return key; } else { - if (RegOpenKeyEx (rootKey, name, 0, KEY_READ, &key) == ERROR_SUCCESS) + if (RegOpenKeyEx (rootKey, name.toUTF16(), 0, KEY_READ, &key) == ERROR_SUCCESS) return key; } } @@ -239269,7 +239351,7 @@ const String PlatformUtilities::getRegistryValue (const String& regValuePath, unsigned long bufferSize = sizeof (buffer); DWORD type = REG_SZ; - if (RegQueryValueEx (k, valueName, 0, &type, (LPBYTE) buffer, &bufferSize) == ERROR_SUCCESS) + if (RegQueryValueEx (k, valueName.toUTF16(), 0, &type, (LPBYTE) buffer, &bufferSize) == ERROR_SUCCESS) { if (type == REG_SZ) result = buffer; @@ -239291,9 +239373,9 @@ void PlatformUtilities::setRegistryValue (const String& regValuePath, if (k != 0) { - RegSetValueEx (k, valueName, 0, REG_SZ, - (const BYTE*) (const WCHAR*) value, - sizeof (WCHAR) * (value.length() + 1)); + RegSetValueEx (k, valueName.toUTF16(), 0, REG_SZ, + (const BYTE*) value.toUTF16().getAddress(), + CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer())); RegCloseKey (k); } @@ -239311,7 +239393,7 @@ bool PlatformUtilities::registryValueExists (const String& regValuePath) unsigned long bufferSize = sizeof (buffer); DWORD type = 0; - if (RegQueryValueEx (k, valueName, 0, &type, buffer, &bufferSize) == ERROR_SUCCESS) + if (RegQueryValueEx (k, valueName.toUTF16(), 0, &type, buffer, &bufferSize) == ERROR_SUCCESS) exists = true; RegCloseKey (k); @@ -239327,7 +239409,7 @@ void PlatformUtilities::deleteRegistryValue (const String& regValuePath) if (k != 0) { - RegDeleteValue (k, valueName); + RegDeleteValue (k, valueName.toUTF16()); RegCloseKey (k); } } @@ -239339,7 +239421,7 @@ void PlatformUtilities::deleteRegistryKey (const String& regKeyPath) if (k != 0) { - RegDeleteKey (k, valueName); + RegDeleteKey (k, valueName.toUTF16()); RegCloseKey (k); } } @@ -239673,7 +239755,7 @@ void MessageManager::doPlatformSpecificInitialisation() wc.lpfnWndProc = (WNDPROC) juce_MessageWndProc; wc.cbWndExtra = 4; wc.hInstance = hmod; - wc.lpszClassName = className; + wc.lpszClassName = className.toUTF16(); RegisterClassEx (&wc); @@ -239686,7 +239768,7 @@ void MessageManager::doPlatformSpecificInitialisation() void MessageManager::doPlatformSpecificShutdown() { DestroyWindow (juce_messageWindowHandle); - UnregisterClass (getMessageWindowClassName(), 0); + UnregisterClass (getMessageWindowClassName().toUTF16(), 0); OleUninitialize(); } @@ -239733,7 +239815,7 @@ static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe, lf.lfPitchAndFamily = FF_DONTCARE; const String fontName (lpelfe->elfLogFont.lfFaceName); - fontName.copyToUnicode (lf.lfFaceName, LF_FACESIZE - 1); + fontName.copyToUTF16 (lf.lfFaceName, LF_FACESIZE - 1); HDC dc = CreateCompatibleDC (0); EnumFontFamiliesEx (dc, &lf, @@ -239836,7 +239918,7 @@ public: lfw.lfQuality = PROOF_QUALITY; lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE); lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL; - fontName.copyToUnicode (lfw.lfFaceName, LF_FACESIZE - 1); + fontName.copyToUTF16 (lfw.lfFaceName, LF_FACESIZE - 1); lfw.lfHeight = size > 0 ? size : -256; HFONT standardSizedFont = CreateFontIndirect (&lfw); @@ -241452,7 +241534,7 @@ public: void setTitle (const String& title) { - SetWindowText (hwnd, title); + SetWindowText (hwnd, title.toUTF16()); } void setPosition (int x, int y) @@ -241814,7 +241896,7 @@ public: if (taskBarIcon != 0) { taskBarIcon->uFlags = NIF_TIP; - toolTip.copyToUnicode (taskBarIcon->szTip, sizeof (taskBarIcon->szTip) - 1); + toolTip.copyToUTF16 (taskBarIcon->szTip, sizeof (taskBarIcon->szTip) - 1); Shell_NotifyIcon (NIM_MODIFY, taskBarIcon); } } @@ -241983,7 +242065,7 @@ private: wcex.cbSize = sizeof (wcex); wcex.style = CS_OWNDC; wcex.lpfnWndProc = (WNDPROC) windowProc; - wcex.lpszClassName = windowClassName; + wcex.lpszClassName = windowClassName.toUTF16(); wcex.cbClsExtra = 0; wcex.cbWndExtra = 32; wcex.hInstance = moduleHandle; @@ -242000,7 +242082,7 @@ private: ~WindowClassHolder() { if (ComponentPeer::getNumPeers() == 0) - UnregisterClass (windowClassName, (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle()); + UnregisterClass (windowClassName.toUTF16(), (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle()); clearSingletonInstance(); } @@ -242065,7 +242147,7 @@ private: && Desktop::canUseSemiTransparentWindows()) exstyle |= WS_EX_LAYERED; - hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->windowClassName, L"", type, 0, 0, 0, 0, + hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->windowClassName.toUTF16(), L"", type, 0, 0, 0, 0, parentToAddTo, 0, (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), 0); #if JUCE_DIRECT2D @@ -243324,7 +243406,7 @@ bool AlertWindow::showNativeDialogBox (const String& title, const String& bodyText, bool isOkCancel) { - return MessageBox (0, bodyText, title, + return MessageBox (0, bodyText.toUTF16(), title.toUTF16(), MB_SETFOREGROUND | (isOkCancel ? MB_OKCANCEL : MB_OK)) == IDOK; } @@ -243468,13 +243550,10 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const const Image juce_createIconForFile (const File& file) { Image image; - - WCHAR filename [1024]; - file.getFullPathName().copyToUnicode (filename, 1023); WORD iconNum = 0; HICON icon = ExtractAssociatedIcon ((HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), - filename, &iconNum); + const_cast (file.getFullPathName().toUTF16().getAddress()), &iconNum); if (icon != 0) { @@ -243784,12 +243863,11 @@ private: static HDROP createHDrop (const StringArray& fileNames) { - int totalChars = 0; + int totalBytes = 0; for (int i = fileNames.size(); --i >= 0;) - totalChars += fileNames[i].length() + 1; + totalBytes += CharPointer_UTF16::getBytesRequiredFor (fileNames[i].getCharPointer()) + sizeof (WCHAR); - HDROP hDrop = (HDROP) GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, - sizeof (DROPFILES) + sizeof (WCHAR) * (totalChars + 2)); + HDROP hDrop = (HDROP) GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (DROPFILES) + totalBytes + 4); if (hDrop != 0) { @@ -243801,8 +243879,8 @@ static HDROP createHDrop (const StringArray& fileNames) for (int i = 0; i < fileNames.size(); ++i) { - fileNames[i].copyToUnicode (fname, 2048); - fname += fileNames[i].length() + 1; + const int bytesWritten = fileNames[i].copyToUTF16 (fname, 2048); + fname = reinterpret_cast (addBytesToPointer (fname, bytesWritten)); } *fname = 0; @@ -243843,12 +243921,12 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text) FORMATETC format = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM medium = { TYMED_HGLOBAL, { 0 }, 0 }; - const int numChars = text.length(); + const int numBytes = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer()); - medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, (numChars + 2) * sizeof (WCHAR)); + medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, numBytes + 2); WCHAR* const data = static_cast (GlobalLock (medium.hGlobal)); - text.copyToUnicode (data, numChars + 1); + text.copyToUTF16 (data, numBytes); format.cfFormat = CF_UNICODETEXT; GlobalUnlock (medium.hGlobal); @@ -243892,7 +243970,7 @@ namespace FileChooserHelpers FileChooserCallbackInfo* info = (FileChooserCallbackInfo*) lpData; if (msg == BFFM_INITIALIZED) - SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) static_cast (info->initialPath)); + SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) info->initialPath.toUTF16().getAddress()); else if (msg == BFFM_VALIDATEFAILEDW) info->returnedString = (LPCWSTR) lParam; else if (msg == BFFM_VALIDATEFAILEDA) @@ -244009,7 +244087,7 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, } else { - currentFileOrDirectory.getFileName().copyToUnicode (files, charsAvailableForResult); + currentFileOrDirectory.getFileName().copyToUTF16 (files, charsAvailableForResult * sizeof (WCHAR)); info.initialPath = currentFileOrDirectory.getParentDirectory().getFullPathName(); } @@ -244020,7 +244098,7 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, bi.hwndOwner = (HWND) parentWindow.getWindowHandle(); bi.pszDisplayName = files; - bi.lpszTitle = title; + bi.lpszTitle = title.toUTF16(); bi.lParam = (LPARAM) &info; bi.lpfn = browseCallbackProc; #ifdef BIF_USENEWUI @@ -244065,10 +244143,11 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, info.customComponent->enterModalState(); } - WCHAR filters [1024]; - zerostruct (filters); - filter.copyToUnicode (filters, 1024); - filter.copyToUnicode (filters + filter.length() + 1, 1022 - filter.length()); + const int filterSpace = 2048; + HeapBlock filters; + filters.calloc (filterSpace * 2); + const int bytesWritten = filter.copyToUTF16 (reinterpret_cast (filters.getData()), filterSpace); + filter.copyToUTF16 (reinterpret_cast (filters + bytesWritten), filterSpace); OPENFILENAMEW of; zerostruct (of); @@ -244079,12 +244158,12 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, of.lStructSize = sizeof (of); #endif of.hwndOwner = (HWND) parentWindow.getWindowHandle(); - of.lpstrFilter = filters; + of.lpstrFilter = reinterpret_cast (filters.getData()); of.nFilterIndex = 1; of.lpstrFile = files; of.nMaxFile = charsAvailableForResult; - of.lpstrInitialDir = info.initialPath; - of.lpstrTitle = title; + of.lpstrInitialDir = info.initialPath.toUTF16(); + of.lpstrTitle = title.toUTF16(); of.Flags = flags; of.lCustData = (LPARAM) &info; @@ -244129,17 +244208,16 @@ void SystemClipboard::copyTextToClipboard (const String& text) { if (EmptyClipboard() != 0) { - const int len = text.length(); + const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer()); - if (len > 0) + if (bytesNeeded > 0) { - HGLOBAL bufH = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, - (len + 1) * sizeof (wchar_t)); + HGLOBAL bufH = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, bytesNeeded + sizeof (WCHAR)); if (bufH != 0) { WCHAR* const data = static_cast (GlobalLock (bufH)); - text.copyToUnicode (data, len); + text.copyToUTF16 (data, bytesNeeded); GlobalUnlock (bufH); SetClipboardData (CF_UNICODETEXT, bufH); @@ -245100,7 +245178,7 @@ public: if (headers != 0) { V_VT (&headersVar) = VT_BSTR; - V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n")); + V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n").toUTF16().getAddress()); } if (postData != 0 && postData->getSize() > 0) @@ -245128,7 +245206,7 @@ public: } } - browser->Navigate ((BSTR) (const OLECHAR*) url, + browser->Navigate ((BSTR) (const OLECHAR*) url.toUTF16().getAddress(), &flags, &frame, &postDataVar, &headersVar); @@ -257088,7 +257166,7 @@ public: void setTitle (const String& title) { XTextProperty nameProperty; - char* strings[] = { const_cast (title.toUTF8()) }; + char* strings[] = { const_cast (title.toUTF8().getAddress()) }; ScopedXLock xlock; if (XStringListToTextProperty (strings, 1, &nameProperty)) @@ -262111,34 +262189,25 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr) { - const int len = s.length(); + const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (s.getCharPointer()); - HeapBlock tempIn, tempOut; - tempIn.calloc (len + 2); - tempOut.calloc (len + 2); - - for (int i = 0; i <= len; ++i) - tempIn[i] = s[i]; + HeapBlock tempOut; + tempOut.calloc (bytesNeeded + 4); ByteCount bytesRead = 0; ByteCount outputBufferSize = 0; if (ConvertFromUnicodeToText (conversionInfo, - len * sizeof (UniChar), tempIn, + bytesNeeded, (ConstUniCharArrayPtr) s.toUTF16().getAddress(), kUnicodeDefaultDirectionMask, 0, 0, 0, 0, - len * sizeof (UniChar), &bytesRead, + bytesNeeded, &bytesRead, &outputBufferSize, tempOut) == noErr) { result.preallocateStorage (bytesRead / sizeof (UniChar) + 2); - juce_wchar* t = result; - - unsigned int i; - for (i = 0; i < bytesRead / sizeof (UniChar); ++i) - t[i] = (juce_wchar) tempOut[i]; - - t[i] = 0; + CharPointer_UTF32 dest (static_cast (result)); + dest.writeAll (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData())); } DisposeUnicodeToTextInfo (&conversionInfo); @@ -264232,7 +264301,7 @@ void File::revealToUser() const #if ! JUCE_IOS bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path) { - return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr; + return FSPathMakeRef (reinterpret_cast (path.toUTF8().getAddress()), destFSRef, 0) == noErr; } const String PlatformUtilities::makePathFromFSRef (FSRef* file) diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 2a683be890..c84f01e511 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 18 +#define JUCE_BUILDNUMBER 20 /** Current Juce version number. @@ -1641,6 +1641,11 @@ inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destB #if JUCE_ANDROID && ! DOXYGEN typedef uint32 juce_wchar; #define JUCE_T(stringLiteral) CharPointer_UTF8 (stringLiteral) + #define JUCE_NATIVE_WCHAR_IS_NOT_UTF32 1 +#elif JUCE_WINDOWS && ! DOXYGEN + typedef uint32 juce_wchar; + #define JUCE_T(stringLiteral) L##stringLiteral + #define JUCE_NATIVE_WCHAR_IS_NOT_UTF32 1 #else /** A platform-independent unicode character type. */ typedef wchar_t juce_wchar; @@ -1854,52 +1859,70 @@ public: 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 - static void copyAndAdvance (DestCharPointerType& dest, SrcCharPointerType src) throw() + template + static size_t lengthUpTo (const CharPointerType& text, const size_t maxCharsToCount) throw() { - juce_wchar c; + size_t len = 0; + CharPointerType t (text); + + while (len < maxCharsToCount && t.getAndAdvance() != 0) + ++len; - do + return len; + } + + template + static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) throw() + { + for (;;) { - c = src.getAndAdvance(); + const juce_wchar c = src.getAndAdvance(); + + if (c == 0) + break; + dest.write (c); } - while (c != 0); + + dest.writeNull(); } template - static int copyAndAdvanceUpToBytes (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) throw() + static int copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) throw() { int numBytesDone = 0; + maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null) for (;;) { const juce_wchar c = src.getAndAdvance(); - const size_t bytesNeeded = DestCharPointerType::getBytesRequiredFor (c); + const int bytesNeeded = (int) DestCharPointerType::getBytesRequiredFor (c); maxBytes -= bytesNeeded; - if (maxBytes < 0) + if (c == 0 || maxBytes < 0) break; numBytesDone += bytesNeeded; dest.write (c); - if (c == 0) - break; } + dest.writeNull(); return numBytesDone; } template - static void copyAndAdvanceUpToNumChars (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) throw() + static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) throw() { - while (--maxChars >= 0) + while (--maxChars > 0) { const juce_wchar c = src.getAndAdvance(); - dest.write (c); if (c == 0) break; + + dest.write (c); } + + dest.writeNull(); } template @@ -1982,7 +2005,7 @@ public: static int indexOf (CharPointerType1 haystack, const CharPointerType2& needle) throw() { int index = 0; - const int needleLength = needle.length(); + const int needleLength = (int) needle.length(); for (;;) { @@ -2054,191 +2077,542 @@ private: #endif -/*** Start of inlined file: juce_CharPointer_UTF8.h ***/ -#ifndef __JUCE_CHARPOINTER_UTF8_JUCEHEADER__ -#define __JUCE_CHARPOINTER_UTF8_JUCEHEADER__ +/*** Start of inlined file: juce_Atomic.h ***/ +#ifndef __JUCE_ATOMIC_JUCEHEADER__ +#define __JUCE_ATOMIC_JUCEHEADER__ /** - Wraps a pointer to a null-terminated UTF-8 character string, and provides - various methods to operate on the data. - @see CharPointer_UTF16, CharPointer_UTF32 + Simple class to hold a primitive value and perform atomic operations on it. + + The type used must be a 32 or 64 bit primitive, like an int, pointer, etc. + There are methods to perform most of the basic atomic operations. */ -class CharPointer_UTF8 +template +class Atomic { public: - typedef char CharType; - - inline CharPointer_UTF8 (const CharType* const rawPointer) throw() - : data (const_cast (rawPointer)) + /** Creates a new value, initialised to zero. */ + inline Atomic() throw() + : value (0) { } - inline CharPointer_UTF8 (const CharPointer_UTF8& other) throw() - : data (other.data) + /** Creates a new value, with a given initial value. */ + inline Atomic (const Type initialValue) throw() + : value (initialValue) { } - inline CharPointer_UTF8& operator= (const CharPointer_UTF8& other) throw() + /** Copies another value (atomically). */ + inline Atomic (const Atomic& other) throw() + : value (other.get()) { - data = other.data; - return *this; } - /** Returns the address that this pointer is pointing to. */ - inline CharType* getAddress() 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. */ - juce_wchar operator*() const throw() + /** Destructor. */ + inline ~Atomic() throw() { - const char byte = *data; + // This class can only be used for types which are 32 or 64 bits in size. + static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8); + } - if (byte >= 0) - return byte; + /** Atomically reads and returns the current value. */ + Type get() const throw(); - juce_wchar n = byte; - juce_wchar mask = 0x7f; - juce_wchar bit = 0x40; - size_t numExtraValues = 0; + /** Copies another value onto this one (atomically). */ + inline Atomic& operator= (const Atomic& other) throw() { exchange (other.get()); return *this; } - while ((n & bit) != 0 && bit > 0x10) - { - mask >>= 1; - ++numExtraValues; - bit >>= 1; - } + /** Copies another value onto this one (atomically). */ + inline Atomic& operator= (const Type newValue) throw() { exchange (newValue); return *this; } - n &= mask; + /** Atomically sets the current value. */ + void set (Type newValue) throw() { exchange (newValue); } - for (size_t i = 1; i <= numExtraValues; ++i) - { - const juce_wchar nextByte = data [i]; + /** Atomically sets the current value, returning the value that was replaced. */ + Type exchange (Type value) throw(); - if ((nextByte & 0xc0) != 0x80) - break; + /** Atomically adds a number to this value, returning the new value. */ + Type operator+= (Type amountToAdd) throw(); - n <<= 6; - n |= (nextByte & 0x3f); - } + /** Atomically subtracts a number from this value, returning the new value. */ + Type operator-= (Type amountToSubtract) throw(); - return n; - } + /** Atomically increments this value, returning the new value. */ + Type operator++() throw(); - /** Moves this pointer along to the next character in the string. */ - CharPointer_UTF8& operator++() throw() - { - const char n = *data++; + /** Atomically decrements this value, returning the new value. */ + Type operator--() throw(); - if (n < 0) - { - juce_wchar bit = 0x40; + /** Atomically compares this value with a target value, and if it is equal, sets + this to be equal to a new value. - while ((n & bit) != 0 && bit > 0x10) + This operation is the atomic equivalent of doing this: + @code + bool compareAndSetBool (Type newValue, Type valueToCompare) + { + if (get() == valueToCompare) { - ++data; - bit >>= 1; + set (newValue); + return true; } - } - - 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() - { - const char byte = *data++; + return false; + } + @endcode - if (byte >= 0) - return byte; + @returns true if the comparison was true and the value was replaced; false if + the comparison failed and the value was left unchanged. + @see compareAndSetValue + */ + bool compareAndSetBool (Type newValue, Type valueToCompare) throw(); - uint32 n = (uint32) (uint8) byte; - uint32 mask = 0x7f; - uint32 bit = 0x40; - int numExtraValues = 0; + /** Atomically compares this value with a target value, and if it is equal, sets + this to be equal to a new value. - while ((n & bit) != 0 && bit > 0x10) + This operation is the atomic equivalent of doing this: + @code + Type compareAndSetValue (Type newValue, Type valueToCompare) { - mask >>= 1; - ++numExtraValues; - bit >>= 1; + Type oldValue = get(); + if (oldValue == valueToCompare) + set (newValue); + + return oldValue; } + @endcode - n &= mask; + @returns the old value before it was changed. + @see compareAndSetBool + */ + Type compareAndSetValue (Type newValue, Type valueToCompare) throw(); - while (--numExtraValues >= 0) - { - const uint32 nextByte = (uint32) (uint8) *data++; + /** Implements a memory read/write barrier. */ + static void memoryBarrier() throw(); - if ((nextByte & 0xc0) != 0x80) - break; + JUCE_ALIGN(8) - n <<= 6; - n |= (nextByte & 0x3f); - } + /** The raw value that this class operates on. + This is exposed publically in case you need to manipulate it directly + for performance reasons. + */ + volatile Type value; - return (juce_wchar) n; - } +private: + static inline Type castFrom32Bit (int32 value) throw() { return *(Type*) &value; } + static inline Type castFrom64Bit (int64 value) throw() { return *(Type*) &value; } + static inline int32 castTo32Bit (Type value) throw() { return *(int32*) &value; } + static inline int64 castTo64Bit (Type value) throw() { return *(int64*) &value; } - /** Moves this pointer along to the next character in the string. */ - CharPointer_UTF8 operator++ (int) throw() - { - CharPointer_UTF8 temp (*this); - ++*this; - return temp; - } + Type operator++ (int); // better to just use pre-increment with atomics.. + Type operator-- (int); +}; - /** Moves this pointer forwards by the specified number of characters. */ - void operator+= (int numToSkip) throw() - { - jassert (numToSkip >= 0); +/* + The following code is in the header so that the atomics can be inlined where possible... +*/ +#if (JUCE_IOS && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2 || ! defined (__IPHONE_3_2))) \ + || (JUCE_MAC && (JUCE_PPC || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))) + #define JUCE_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier - while (--numToSkip >= 0) - ++*this; - } + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 + #define JUCE_MAC_ATOMICS_VOLATILE + #else + #define JUCE_MAC_ATOMICS_VOLATILE volatile + #endif - /** Returns the character at a given character index from the start of the string. */ - juce_wchar operator[] (int characterIndex) const throw() - { - CharPointer_UTF8 p (*this); - p += characterIndex; - return *p; - } + #if JUCE_PPC || JUCE_IOS + // None of these atomics are available for PPC or for iPhoneOS 3.1 or earlier!! + template static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return *a += b; } + template static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return ++*a; } + template static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return --*a; } + template static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) throw() + { jassertfalse; if (old == *value) { *value = newValue; return true; } return false; } + #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 + #endif - /** Returns a pointer which is moved forwards from this one by the specified number of characters. */ - CharPointer_UTF8 operator+ (int numToSkip) const throw() - { - CharPointer_UTF8 p (*this); - p += numToSkip; - return p; - } +#elif JUCE_GCC + #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics - /** Writes a unicode character to this string, and advances this pointer to point to the next position. */ - void write (const juce_wchar charToWrite) throw() - { - const uint32 c = (uint32) charToWrite; + #if JUCE_IOS + #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 // (on the iphone, the 64-bit ops will compile but not link) + #endif - if (c >= 0x80) - { - int numExtraBytes = 1; - if (c >= 0x800) +#else + #define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics + + #if JUCE_USE_INTRINSICS || JUCE_64BIT + #pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \ + _InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier) + #define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b) + #define juce_InterlockedIncrement(a) _InterlockedIncrement(a) + #define juce_InterlockedDecrement(a) _InterlockedDecrement(a) + #define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b) + #define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c) + #define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c) + #define juce_MemoryBarrier _ReadWriteBarrier + #else + // (these are defined in juce_win32_Threads.cpp) + long juce_InterlockedExchange (volatile long* a, long b) throw(); + long juce_InterlockedIncrement (volatile long* a) throw(); + long juce_InterlockedDecrement (volatile long* a) throw(); + long juce_InterlockedExchangeAdd (volatile long* a, long b) throw(); + long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); + __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw(); + inline void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); } + #endif + + #if JUCE_64BIT + #pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64) + #define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b) + #define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b) + #define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a) + #define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a) + #else + // None of these atomics are available in a 32-bit Windows build!! + template static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a += b; return old; } + template static Type juce_InterlockedExchange64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a = b; return old; } + template static Type juce_InterlockedIncrement64 (volatile Type* a) throw() { jassertfalse; return ++*a; } + template static Type juce_InterlockedDecrement64 (volatile Type* a) throw() { jassertfalse; return --*a; } + #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 + #endif +#endif + +#if JUCE_MSVC + #pragma warning (push) + #pragma warning (disable: 4311) // (truncation warning) +#endif + +template +inline Type Atomic::get() const throw() +{ + #if JUCE_ATOMICS_MAC + return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)) + : castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value)); + #elif JUCE_ATOMICS_WINDOWS + return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0)) + : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0)); + #elif JUCE_ANDROID + return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (value), castTo32Bit (value), (volatile int*) &value)); + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) + : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); + #endif +} + +template +inline Type Atomic::exchange (const Type newValue) throw() +{ + #if JUCE_ANDROID + return castFrom32Bit (__atomic_swap (castTo32Bit (newValue), (volatile int*) &value)); + #elif JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC + Type currentVal = value; + while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; } + return currentVal; + #elif JUCE_ATOMICS_WINDOWS + return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue))) + : castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue))); + #endif +} + +template +inline Type Atomic::operator+= (const Type amountToAdd) throw() +{ + #if JUCE_ATOMICS_MAC + return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) + : (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); + #elif JUCE_ATOMICS_WINDOWS + return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd) + : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd); + #elif JUCE_ANDROID + for (;;) + { + const Type oldValue (value); + const Type newValue (oldValue + amountToAdd); + if (compareAndSetBool (newValue, oldValue)) + return newValue; + } + #elif JUCE_ATOMICS_GCC + return (Type) __sync_add_and_fetch (&value, amountToAdd); + #endif +} + +template +inline Type Atomic::operator-= (const Type amountToSubtract) throw() +{ + return operator+= (juce_negate (amountToSubtract)); +} + +template +inline Type Atomic::operator++() throw() +{ + #if JUCE_ATOMICS_MAC + return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) + : (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); + #elif JUCE_ATOMICS_WINDOWS + return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) + : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); + #elif JUCE_ANDROID + return (Type) __atomic_inc (&value); + #elif JUCE_ATOMICS_GCC + return (Type) __sync_add_and_fetch (&value, 1); + #endif +} + +template +inline Type Atomic::operator--() throw() +{ + #if JUCE_ATOMICS_MAC + return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) + : (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); + #elif JUCE_ATOMICS_WINDOWS + return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) + : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); + #elif JUCE_ANDROID + return (Type) __atomic_dec (&value); + #elif JUCE_ATOMICS_GCC + return (Type) __sync_add_and_fetch (&value, -1); + #endif +} + +template +inline bool Atomic::compareAndSetBool (const Type newValue, const Type valueToCompare) throw() +{ + #if JUCE_ATOMICS_MAC + return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) + : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); + #elif JUCE_ATOMICS_WINDOWS || JUCE_ANDROID + return compareAndSetValue (newValue, valueToCompare) == valueToCompare; + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) + : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); + #endif +} + +template +inline Type Atomic::compareAndSetValue (const Type newValue, const Type valueToCompare) throw() +{ + #if JUCE_ATOMICS_MAC + for (;;) // Annoying workaround for OSX only having a bool CAS operation.. + { + if (compareAndSetBool (newValue, valueToCompare)) + return valueToCompare; + + const Type result = value; + if (result != valueToCompare) + return result; + } + + #elif JUCE_ATOMICS_WINDOWS + return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare))) + : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare))); + #elif JUCE_ANDROID + return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value)); + #elif JUCE_ATOMICS_GCC + return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) + : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); + #endif +} + +template +inline void Atomic::memoryBarrier() throw() +{ + #if JUCE_ATOMICS_MAC + OSMemoryBarrier(); + #elif JUCE_ATOMICS_GCC + __sync_synchronize(); + #elif JUCE_ATOMICS_WINDOWS + juce_MemoryBarrier(); + #endif +} + +#if JUCE_MSVC + #pragma warning (pop) +#endif + +#endif // __JUCE_ATOMIC_JUCEHEADER__ +/*** End of inlined file: juce_Atomic.h ***/ + + +/*** Start of inlined file: juce_CharPointer_UTF8.h ***/ +#ifndef __JUCE_CHARPOINTER_UTF8_JUCEHEADER__ +#define __JUCE_CHARPOINTER_UTF8_JUCEHEADER__ + +/** + Wraps a pointer to a null-terminated UTF-8 character string, and provides + various methods to operate on the data. + @see CharPointer_UTF16, CharPointer_UTF32 +*/ +class CharPointer_UTF8 +{ +public: + typedef char CharType; + + inline explicit CharPointer_UTF8 (const CharType* const rawPointer) throw() + : data (const_cast (rawPointer)) + { + } + + inline CharPointer_UTF8 (const CharPointer_UTF8& other) throw() + : data (other.data) + { + } + + inline CharPointer_UTF8& operator= (const CharPointer_UTF8& other) throw() + { + data = other.data; + return *this; + } + + inline CharPointer_UTF8& 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_UTF8& other) const throw() + { + return data == other.data; + } + + /** This is a pointer comparison, it doesn't compare the actual text. */ + inline bool operator!= (const CharPointer_UTF8& other) const throw() + { + return data == other.data; + } + + /** 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. */ + juce_wchar operator*() const throw() + { + const char byte = *data; + + if (byte >= 0) + return byte; + + juce_wchar n = byte; + juce_wchar mask = 0x7f; + juce_wchar bit = 0x40; + size_t numExtraValues = 0; + + while ((n & bit) != 0 && bit > 0x10) + { + mask >>= 1; + ++numExtraValues; + bit >>= 1; + } + + n &= mask; + + for (size_t i = 1; i <= numExtraValues; ++i) + { + const juce_wchar nextByte = data [i]; + + if ((nextByte & 0xc0) != 0x80) + break; + + n <<= 6; + n |= (nextByte & 0x3f); + } + + return n; + } + + /** Moves this pointer along to the next character in the string. */ + CharPointer_UTF8& operator++() throw() + { + const char n = *data++; + + if (n < 0) + { + juce_wchar bit = 0x40; + + while ((n & bit) != 0 && bit > 0x8) { - ++numExtraBytes; - if (c >= 0x10000) - ++numExtraBytes; + ++data; + bit >>= 1; } + } + + 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() + { + const char byte = *data++; + + if (byte >= 0) + return byte; + + uint32 n = (uint32) (uint8) byte; + uint32 mask = 0x7f; + uint32 bit = 0x40; + int numExtraValues = 0; + + while ((n & bit) != 0 && bit > 0x8) + { + mask >>= 1; + ++numExtraValues; + bit >>= 1; + } - *data++ = (CharType) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); + n &= mask; - while (--numExtraBytes >= 0) - *data++ = (CharType) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); - } - else + while (--numExtraValues >= 0) { - *data++ = (CharType) c; + const uint32 nextByte = (uint32) (uint8) *data++; + + if ((nextByte & 0xc0) != 0x80) + break; + + n <<= 6; + n |= (nextByte & 0x3f); } + + return (juce_wchar) n; + } + + /** Moves this pointer along to the next character in the string. */ + CharPointer_UTF8 operator++ (int) throw() + { + CharPointer_UTF8 temp (*this); + ++*this; + return temp; + } + + /** Moves this pointer forwards by the specified number of characters. */ + void operator+= (int numToSkip) throw() + { + jassert (numToSkip >= 0); + + while (--numToSkip >= 0) + ++*this; + } + + /** Returns the character at a given character index from the start of the string. */ + juce_wchar operator[] (int characterIndex) const throw() + { + CharPointer_UTF8 p (*this); + p += characterIndex; + return *p; + } + + /** Returns a pointer which is moved forwards 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. */ @@ -2273,6 +2647,12 @@ public: return count; } + /** 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. */ @@ -2325,27 +2705,65 @@ public: return CharPointer_UTF8 (data + strlen (data)); } + /** Writes a unicode character to this string, and advances this pointer to point to the next position. */ + void write (const juce_wchar charToWrite) throw() + { + const uint32 c = (uint32) charToWrite; + + if (c >= 0x80) + { + int numExtraBytes = 1; + if (c >= 0x800) + { + ++numExtraBytes; + if (c >= 0x10000) + ++numExtraBytes; + } + + *data++ = (CharType) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); + + while (--numExtraBytes >= 0) + *data++ = (CharType) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); + } + else + { + *data++ = (CharType) c; + } + } + + /** Writes a null character to this string (leaving the pointer's position unchanged). */ + inline void writeNull() const throw() + { + *data = 0; + } + /** Copies a source string to this pointer, advancing this pointer as it goes. */ template - void copyAndAdvance (const CharPointer& src) throw() + void writeAll (const CharPointer& src) throw() { - CharacterFunctions::copyAndAdvance (*this, src); + CharacterFunctions::copyAll (*this, src); } /** Copies a source string to this pointer, advancing this pointer as it goes. */ - void copyAndAdvance (const CharPointer_UTF8& src) throw() + void writeAll (const CharPointer_UTF8& src) throw() { - data = (CharType*) strcpy ((char*) data, src.data); + const CharType* s = src.data; + + while ((*data = *s) != 0) + { + ++data; + ++s; + } } /** Copies a source string to this pointer, advancing this pointer as it goes. - The maxBytes parameter specifies the maximum number of bytes that can be written + The maxDestBytes parameter specifies the maximum number of bytes that can be written to the destination buffer before stopping. */ template - int copyAndAdvanceUpToBytes (const CharPointer& src, int maxBytes) throw() + int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw() { - return CharacterFunctions::copyAndAdvanceUpToBytes (*this, src, maxBytes); + return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes); } /** Copies a source string to this pointer, advancing this pointer as it goes. @@ -2353,9 +2771,9 @@ public: written to the destination buffer before stopping (including the terminating null). */ template - void copyAndAdvanceUpToNumChars (const CharPointer& src, int maxChars) throw() + void writeWithCharLimit (const CharPointer& src, const int maxChars) throw() { - CharacterFunctions::copyAndAdvanceUpToNumChars (*this, src, maxChars); + CharacterFunctions::copyWithCharLimit (*this, src, maxChars); } /** Compares this string with another one. */ @@ -2367,7 +2785,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareUpTo (const CharPointer& other, int maxChars) const throw() + int compareUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareUpTo (*this, other, maxChars); } @@ -2391,13 +2809,13 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareIgnoreCaseUpTo (const CharPointer& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); } /** Compares this string with another one, up to a specified number of characters. */ - int compareIgnoreCaseUpTo (const CharPointer_UTF8& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer_UTF8& other, const int maxChars) const throw() { #if JUCE_WINDOWS return strnicmp (data, other.data, maxChars); @@ -2465,6 +2883,14 @@ public: /** Returns the first non-whitespace character in the string. */ CharPointer_UTF8 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); } + /** These values are the byte-order-mark (BOM) values for a UTF-8 stream. */ + enum + { + byteOrderMark1 = 0xef, + byteOrderMark2 = 0xbb, + byteOrderMark3 = 0xbf + }; + private: CharType* data; }; @@ -2485,9 +2911,13 @@ private: class CharPointer_UTF16 { public: + #if JUCE_WINDOWS && ! DOXYGEN + typedef wchar_t CharType; + #else typedef int16 CharType; + #endif - inline CharPointer_UTF16 (const CharType* const rawPointer) throw() + inline explicit CharPointer_UTF16 (const CharType* const rawPointer) throw() : data (const_cast (rawPointer)) { } @@ -2503,9 +2933,30 @@ public: return *this; } + inline CharPointer_UTF16& 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_UTF16& other) const throw() + { + return data == other.data; + } + + /** This is a pointer comparison, it doesn't compare the actual text. */ + inline bool operator!= (const CharPointer_UTF16& other) const throw() + { + return data == other.data; + } + /** 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; } @@ -2514,8 +2965,8 @@ public: { uint32 n = (uint32) (uint16) *data; - if (n >= 0xd800 && n <= 0xdfff) - n = 0x10000 + (((n & ~0xd800) << 10) | (data[1] & ~0xdc00)); + if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) data[1]) >= 0xdc00) + n = 0x10000 + (((n - 0xd800) << 10) | (((uint32) (uint16) data[1]) - 0xdc00)); return (juce_wchar) n; } @@ -2525,7 +2976,7 @@ public: { const juce_wchar n = *data++; - if (n >= 0xd800 && n <= 0xdfff) + if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00) ++data; return *this; @@ -2537,11 +2988,8 @@ public: { uint32 n = (uint32) (uint16) *data++; - if (n >= 0xd800 && n <= 0xdfff) - { - n = 0x10000 + (((n & ~0xd800) << 10) | (*data & ~0xdc00)); - ++data; - } + if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00) + n = 0x10000 + ((((n - 0xd800) << 10) | (((uint32) (uint16) *data++) - 0xdc00))); return (juce_wchar) n; } @@ -2564,7 +3012,7 @@ public: } /** Returns the character at a given character index from the start of the string. */ - juce_wchar operator[] (int characterIndex) const throw() + juce_wchar operator[] (const int characterIndex) const throw() { CharPointer_UTF16 p (*this); p += characterIndex; @@ -2572,7 +3020,7 @@ public: } /** Returns a pointer which is moved forwards from this one by the specified number of characters. */ - CharPointer_UTF16 operator+ (int numToSkip) const throw() + CharPointer_UTF16 operator+ (const int numToSkip) const throw() { CharPointer_UTF16 p (*this); p += numToSkip; @@ -2580,19 +3028,26 @@ public: } /** Writes a unicode character to this string, and advances this pointer to point to the next position. */ - void write (const juce_wchar charToWrite) throw() + void write (juce_wchar charToWrite) throw() { - if (charToWrite < 0xd800 || (charToWrite > 0xdfff && charToWrite <= 0xffff)) + if (charToWrite >= 0x10000) { - *data++ = (CharType) charToWrite; + charToWrite -= 0x10000; + *data++ = (CharType) (0xd800 + (charToWrite >> 10)); + *data++ = (CharType) (0xdc00 + (charToWrite & 0x3ff)); } else { - *data++ = (CharType) ((0xd800 - (0x10000 >> 10)) + (charToWrite >> 10)); - *data++ = (CharType) (0xdc00 + (charToWrite & 0x3ff)); + *data++ = (CharType) charToWrite; } } + /** 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() { @@ -2604,7 +3059,10 @@ public: const int n = *d++; if (n >= 0xd800 && n <= 0xdfff) - ++d; + { + if (*d++ == 0) + break; + } else if (n == 0) break; @@ -2614,6 +3072,12 @@ public: return count; } + /** 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. */ @@ -2627,8 +3091,7 @@ public: */ static size_t getBytesRequiredFor (const juce_wchar charToWrite) throw() { - return (charToWrite < 0xd800 || (charToWrite > 0xdfff && charToWrite <= 0xffff)) - ? 1 : 2; + return (charToWrite >= 0x10000) ? (sizeof (CharType) * 2) : sizeof (CharType); } /** Returns the number of bytes that would be needed to represent the given @@ -2660,13 +3123,13 @@ public: /** Copies a source string to this pointer, advancing this pointer as it goes. */ template - void copyAndAdvance (const CharPointer& src) throw() + void writeAll (const CharPointer& src) throw() { - CharacterFunctions::copyAndAdvance (*this, src); + CharacterFunctions::copyAll (*this, src); } /** Copies a source string to this pointer, advancing this pointer as it goes. */ - void copyAndAdvance (const CharPointer_UTF16& src) throw() + void writeAll (const CharPointer_UTF16& src) throw() { const CharType* s = src.data; @@ -2678,13 +3141,13 @@ public: } /** Copies a source string to this pointer, advancing this pointer as it goes. - The maxBytes parameter specifies the maximum number of bytes that can be written + The maxDestBytes parameter specifies the maximum number of bytes that can be written to the destination buffer before stopping. */ template - int copyAndAdvanceUpToBytes (const CharPointer& src, int maxBytes) throw() + int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw() { - return CharacterFunctions::copyAndAdvanceUpToBytes (*this, src, maxBytes); + return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes); } /** Copies a source string to this pointer, advancing this pointer as it goes. @@ -2692,9 +3155,9 @@ public: written to the destination buffer before stopping (including the terminating null). */ template - void copyAndAdvanceUpToNumChars (const CharPointer& src, int maxChars) throw() + void writeWithCharLimit (const CharPointer& src, const int maxChars) throw() { - CharacterFunctions::copyAndAdvanceUpToNumChars (*this, src, maxChars); + CharacterFunctions::copyWithCharLimit (*this, src, maxChars); } /** Compares this string with another one. */ @@ -2706,7 +3169,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareUpTo (const CharPointer& other, int maxChars) const throw() + int compareUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareUpTo (*this, other, maxChars); } @@ -2720,11 +3183,29 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareIgnoreCaseUpTo (const CharPointer& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); } + #if JUCE_WINDOWS && ! DOXYGEN + int compareIgnoreCase (const CharPointer_UTF16& other) const throw() + { + return _wcsicmp (data, other.data); + } + + int compareIgnoreCaseUpTo (const CharPointer_UTF16& other, int maxChars) const throw() + { + return _wcsnicmp (data, other.data, maxChars); + } + + int indexOf (const CharPointer_UTF16& stringToFind) const throw() + { + const CharType* const t = wcsstr (data, stringToFind.getAddress()); + return t == 0 ? -1 : (int) (t - data); + } + #endif + /** Returns the character index of a substring, or -1 if it isn't found. */ template int indexOf (const CharPointer& stringToFind) const throw() @@ -2764,9 +3245,24 @@ public: juce_wchar toLowerCase() const throw() { return CharacterFunctions::toLowerCase (operator*()); } /** Parses this string as a 32-bit integer. */ - int getIntValue32() const throw() { return CharacterFunctions::getIntValue (*this); } + int getIntValue32() const throw() + { + #if JUCE_WINDOWS + return _wtoi (data); + #else + return CharacterFunctions::getIntValue (*this); + #endif + } + /** Parses this string as a 64-bit integer. */ - int64 getIntValue64() const throw() { return CharacterFunctions::getIntValue (*this); } + int64 getIntValue64() const throw() + { + #if JUCE_WINDOWS + return _wtoi64 (data); + #else + return CharacterFunctions::getIntValue (*this); + #endif + } /** Parses this string as a floating point double. */ double getDoubleValue() const throw() { return CharacterFunctions::getDoubleValue (*this); } @@ -2774,6 +3270,15 @@ public: /** Returns the first non-whitespace character in the string. */ CharPointer_UTF16 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); } + /** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */ + enum + { + byteOrderMarkBE1 = 0xfe, + byteOrderMarkBE2 = 0xff, + byteOrderMarkLE1 = 0xff, + byteOrderMarkLE2 = 0xfe + }; + private: CharType* data; @@ -2806,7 +3311,7 @@ class CharPointer_UTF32 public: typedef juce_wchar CharType; - inline CharPointer_UTF32 (const CharType* const rawPointer) throw() + inline explicit CharPointer_UTF32 (const CharType* const rawPointer) throw() : data (const_cast (rawPointer)) { } @@ -2822,9 +3327,30 @@ public: return *this; } + inline CharPointer_UTF32& 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_UTF32& other) const throw() + { + return data == other.data; + } + + /** This is a pointer comparison, it doesn't compare the actual text. */ + inline bool operator!= (const CharPointer_UTF32& other) const throw() + { + return data == other.data; + } + /** 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; } @@ -2858,30 +3384,30 @@ public: } /** Moves this pointer forwards by the specified number of characters. */ - inline void operator+= (int numToSkip) throw() + inline void operator+= (const int numToSkip) throw() { data += numToSkip; } - inline void operator-= (int numToSkip) throw() + 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[] (int characterIndex) const throw() + inline juce_wchar& operator[] (const int characterIndex) const throw() { return data [characterIndex]; } /** Returns a pointer which is moved forwards from this one by the specified number of characters. */ - CharPointer_UTF32 operator+ (int numToSkip) const throw() + CharPointer_UTF32 operator+ (const int numToSkip) const throw() { return CharPointer_UTF32 (data + numToSkip); } /** Returns a pointer which is moved backwards from this one by the specified number of characters. */ - CharPointer_UTF32 operator- (int numToSkip) const throw() + CharPointer_UTF32 operator- (const int numToSkip) const throw() { return CharPointer_UTF32 (data - numToSkip); } @@ -2892,12 +3418,23 @@ public: *data++ = charToWrite; } + inline void replaceChar (const juce_wchar newChar) throw() + { + *data = 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() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 size_t n = 0; - while (data[n] == 0) + while (data[n] != 0) ++n; return n; #else @@ -2905,6 +3442,12 @@ public: #endif } + /** 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. */ @@ -2939,27 +3482,31 @@ public: /** Copies a source string to this pointer, advancing this pointer as it goes. */ template - void copyAndAdvance (const CharPointer& src) throw() + void writeAll (const CharPointer& src) throw() { - CharacterFunctions::copyAndAdvance (*this, src); + CharacterFunctions::copyAll (*this, src); } - #if ! JUCE_ANDROID /** Copies a source string to this pointer, advancing this pointer as it goes. */ - void copyAndAdvance (const CharPointer_UTF32& src) throw() + void writeAll (const CharPointer_UTF32& src) throw() { - data = wcscpy (data, src.data); + const CharType* s = src.data; + + while ((*data = *s) != 0) + { + ++data; + ++s; + } } - #endif /** Copies a source string to this pointer, advancing this pointer as it goes. - The maxBytes parameter specifies the maximum number of bytes that can be written + The maxDestBytes parameter specifies the maximum number of bytes that can be written to the destination buffer before stopping. */ template - int copyAndAdvanceUpToBytes (const CharPointer& src, int maxBytes) throw() + int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw() { - return CharacterFunctions::copyAndAdvanceUpToBytes (*this, src, maxBytes); + return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes); } /** Copies a source string to this pointer, advancing this pointer as it goes. @@ -2967,9 +3514,9 @@ public: written to the destination buffer before stopping (including the terminating null). */ template - void copyAndAdvanceUpToNumChars (const CharPointer& src, int maxChars) throw() + void writeWithCharLimit (const CharPointer& src, const int maxChars) throw() { - CharacterFunctions::copyAndAdvanceUpToNumChars (*this, src, maxChars); + CharacterFunctions::copyWithCharLimit (*this, src, maxChars); } /** Compares this string with another one. */ @@ -2979,7 +3526,7 @@ public: return CharacterFunctions::compare (*this, other); } - #if ! JUCE_ANDROID + #if ! JUCE_NATIVE_WCHAR_IS_NOT_UTF32 /** Compares this string with another one. */ int compare (const CharPointer_UTF32& other) const throw() { @@ -2989,7 +3536,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareUpTo (const CharPointer& other, int maxChars) const throw() + int compareUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareUpTo (*this, other, maxChars); } @@ -3003,7 +3550,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareIgnoreCaseUpTo (const CharPointer& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); } @@ -3038,24 +3585,6 @@ public: : CharacterFunctions::indexOfChar (*this, charToFind); } - #if JUCE_WINDOWS && ! DOXYGEN - int compareIgnoreCase (const CharPointer_UTF32& other) const throw() - { - return _wcsicmp (data, other.data); - } - - int compareIgnoreCaseUpTo (const CharPointer_UTF32& other, int maxChars) const throw() - { - return _wcsnicmp (data, other.data, maxChars); - } - - int indexOf (const CharPointer_UTF32& stringToFind) const throw() - { - const CharType* const t = wcsstr (data, stringToFind.getAddress()); - return t == 0 ? -1 : (t - data); - } - #endif - /** 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. */ @@ -3075,24 +3604,9 @@ public: juce_wchar toLowerCase() const throw() { return CharacterFunctions::toLowerCase (*data); } /** Parses this string as a 32-bit integer. */ - int getIntValue32() const throw() - { - #if JUCE_WINDOWS - return _wtoi (data); - #else - return CharacterFunctions::getIntValue (*this); - #endif - } - + int getIntValue32() const throw() { return CharacterFunctions::getIntValue (*this); } /** Parses this string as a 64-bit integer. */ - int64 getIntValue64() const throw() - { - #if JUCE_WINDOWS - return _wtoi64 (data); - #else - return CharacterFunctions::getIntValue (*this); - #endif - } + int64 getIntValue64() const throw() { return CharacterFunctions::getIntValue (*this); } /** Parses this string as a floating point double. */ double getDoubleValue() const throw() { return CharacterFunctions::getDoubleValue (*this); } @@ -3100,6 +3614,11 @@ public: /** Returns the first non-whitespace character in the string. */ CharPointer_UTF32 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); } + CharPointer_UTF32 atomicSwap (const CharPointer_UTF32& newValue) + { + return CharPointer_UTF32 (reinterpret_cast &> (data).exchange (newValue.data)); + } + private: CharType* data; }; @@ -3157,6 +3676,26 @@ public: */ String (const juce_wchar* unicodeText, size_t maxChars); + /** Creates a string from a UTF-8 character string */ + String (const CharPointer_UTF8& text); + + /** Creates a string from a UTF-16 character string */ + String (const CharPointer_UTF16& text); + + /** Creates a string from a UTF-32 character string */ + String (const CharPointer_UTF32& text); + + /** Creates a string from a UTF-32 character string */ + String (const CharPointer_UTF32& text, size_t maxChars); + + #if JUCE_WINDOWS + /** 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); @@ -3170,6 +3709,9 @@ public: */ static const String empty; + /** This is the character encoding type used internally to store the string. */ + typedef CharPointer_UTF32 CharPointerType; + /** Generates a probably-unique 32-bit hashcode from this string. */ int hashCode() const throw(); @@ -3192,15 +3734,63 @@ public: String& operator+= (char characterToAppend); /** Appends a character at the end of this string. */ String& operator+= (juce_wchar characterToAppend); + #if JUCE_WINDOWS + /** Appends a character at the end of this string. */ + String& operator+= (wchar_t characterToAppend); + /** Appends another string at the end of this one. */ + String& operator+= (const wchar_t* textToAppend); + #endif /** Appends a decimal number at the end of this string. */ String& operator+= (int numberToAppend); - /** Appends a string at the end of this one. + /** Appends a string to the end of this one. + + @param textToAppend the string to add + @param maxCharsToTake the maximum number of characters to take from the string passed in + */ + void append (const String& textToAppend, size_t maxCharsToTake); + + /** Appends a string to the end of this one. + + @param textToAppend the string to add + @param maxCharsToTake the maximum number of characters to take from the string passed in + */ + template + void appendCharPointer (const CharPointer& textToAppend, size_t maxCharsToTake) + { + if (textToAppend.getAddress() != 0) + { + const size_t numExtraChars = textToAppend.lengthUpTo (maxCharsToTake); + + if (numExtraChars > 0) + { + const int oldLen = length(); + preallocateStorage (oldLen + numExtraChars); + CharPointerType (text + oldLen).writeWithCharLimit (textToAppend, (int) (numExtraChars + 1)); + } + } + } + + /** Appends a string to the end of this one. @param textToAppend the string to add @param maxCharsToTake the maximum number of characters to take from the string passed in */ - void append (const juce_wchar* textToAppend, int maxCharsToTake); + template + void appendCharPointer (const CharPointer& textToAppend) + { + if (textToAppend.getAddress() != 0) + { + const size_t numExtraChars = textToAppend.length(); + + if (numExtraChars > 0) + { + const int oldLen = length(); + preallocateStorage (oldLen + numExtraChars); + CharPointerType (text + oldLen).writeAll (textToAppend); + } + } + } // Comparison methods.. @@ -3966,7 +4556,7 @@ public: that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ - inline operator const juce_wchar*() const throw() { return text; } + inline operator const juce_wchar*() const throw() { return text.getAddress(); } /** Returns a unicode version of this string. @@ -3974,7 +4564,15 @@ public: that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ - inline operator juce_wchar*() throw() { return text; } + inline operator juce_wchar*() throw() { return text.getAddress(); } + + /** Returns the character pointer currently being used to store 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 be deleted whenever the + string changes. + */ + inline const CharPointerType& getCharPointer() const throw() { return text; } /** Returns a pointer to a UTF-8 version of this string. @@ -3982,12 +4580,37 @@ public: that is returned must not be stored anywhere, as it can be deleted whenever the string changes. - @see getNumBytesAsUTF8, fromUTF8, copyToUTF8, toCString + To find out how many bytes you need to store this string as UTF-8, you can call + CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer()) + + @see getCharPointer, toUTF16, toUTF32 */ - const char* toUTF8() const; + const CharPointer_UTF8 toUTF8() const; - /** Creates a String from a UTF-8 encoded buffer. + /** Returns a pointer to a UTF-32 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 be deleted whenever the + string changes. + + To find out how many bytes you need to store this string as UTF-16, you can call + CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer()) + @see getCharPointer, toUTF8, toUTF32 + */ + CharPointer_UTF16 toUTF16() const; + + /** Returns a pointer to a UTF-32 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 be deleted whenever the + string changes. + + @see getCharPointer, toUTF8, toUTF16 + */ + inline CharPointer_UTF32 toUTF32() const throw() { return text; } + + /** Creates a String from a UTF-8 encoded buffer. If the size is < 0, it'll keep reading until it hits a zero. */ static const String fromUTF8 (const char* utf8buffer, int bufferSizeBytes = -1); @@ -4003,15 +4626,34 @@ public: Returns the number of bytes copied to the buffer, including the terminating null character. - @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. + To find out how many bytes you need to store this string as UTF-8, you can call + CharPointer_UTF8::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. + @see CharPointer_UTF8::writeWithDestByteLimit + */ + int copyToUTF8 (CharPointer_UTF8::CharType* destBuffer, int maxBufferSizeBytes) const throw(); + + /** Copies the string to a buffer as UTF-16 characters. + + Returns the number of bytes copied to the buffer, including the terminating null + character. + + To find out how many bytes you need to store this string as UTF-16, you can call + CharPointer_UTF16::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. + @see CharPointer_UTF16::writeWithDestByteLimit */ - int copyToUTF8 (char* destBuffer, int maxBufferSizeBytes) const throw(); + 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. @@ -4025,6 +4667,7 @@ public: /** 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(); @@ -4040,15 +4683,6 @@ public: */ int copyToCString (char* destBuffer, int maxBufferSizeBytes) const throw(); - /** Copies the string to a unicode buffer. - - @param destBuffer the place to copy it to - @param maxCharsToCopy the maximum number of characters to copy to the buffer, - NOT including the trailing zero, so this shouldn't be - larger than the size of your destination buffer - 1 - */ - void copyToUnicode (juce_wchar* destBuffer, int maxCharsToCopy) const throw(); - /** Increases the string's internally allocated storage. Although the string's contents won't be affected by this call, it will @@ -4096,7 +4730,7 @@ public: private: - juce_wchar* text; + CharPointerType text; struct Preallocation { @@ -4108,8 +4742,9 @@ private: explicit String (const Preallocation&); String (const String& stringToCopy, size_t charsToAllocate); - void createInternal (const juce_wchar* text, size_t numChars); - void appendInternal (const juce_wchar* text, int numExtraChars); + void appendFixedLength (const juce_wchar* text, int numExtraChars); + + void enlarge (size_t newTotalNumChars); void* createSpaceAtEndOfBuffer (size_t numExtraBytes) const; // This private cast operator should prevent strings being accidentally cast @@ -4137,6 +4772,14 @@ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const juce_wchar JUCE_API const String JUCE_CALLTYPE operator+ (String string1, char characterToAppend); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, juce_wchar characterToAppend); +#if JUCE_WINDOWS +/** Concatenates two strings. */ +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, wchar_t characterToAppend); +/** Concatenates two strings. */ +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const wchar_t* string2); +/** Concatenates two strings. */ +JUCE_API const String JUCE_CALLTYPE operator+ (const wchar_t* string1, const String& string2); +#endif /** Appends a character at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, char characterToAppend); @@ -4167,12 +4810,24 @@ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const char* strin /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const juce_wchar* string2) throw(); /** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF8& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF16& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF32& string2) throw(); +/** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const char* string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const juce_wchar* string2) throw(); /** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF8& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF16& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF32& string2) throw(); +/** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator< (const String& string1, const String& string2) throw(); @@ -4187,437 +4842,81 @@ JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& str template JUCE_API std::basic_ostream & JUCE_CALLTYPE operator<< (std::basic_ostream & stream, const String& stringToWrite) { - return stream << stringToWrite.toUTF8(); + return stream << stringToWrite.toUTF8().getAddress(); } -/** Writes a string to an OutputStream as UTF8. */ -JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& text); - -#endif // __JUCE_STRING_JUCEHEADER__ -/*** End of inlined file: juce_String.h ***/ - -/** - Acts as an application-wide logging class. - - A subclass of Logger can be created and passed into the Logger::setCurrentLogger - method and this will then be used by all calls to writeToLog. - - The logger class also contains methods for writing messages to the debugger's - output stream. - - @see FileLogger -*/ -class JUCE_API Logger -{ -public: - - /** Destructor. */ - virtual ~Logger(); - - /** Sets the current logging class to use. - - Note that the object passed in won't be deleted when no longer needed. - A null pointer can be passed-in to disable any logging. - - If deleteOldLogger is set to true, the existing logger will be - deleted (if there is one). - */ - static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger, - bool deleteOldLogger = false); - - /** Writes a string to the current logger. - - This will pass the string to the logger's logMessage() method if a logger - has been set. - - @see logMessage - */ - static void JUCE_CALLTYPE writeToLog (const String& message); - - /** Writes a message to the standard error stream. - - This can be called directly, or by using the DBG() macro in - juce_PlatformDefs.h (which will avoid calling the method in non-debug builds). - */ - static void JUCE_CALLTYPE outputDebugString (const String& text); - -protected: - - Logger(); - - /** This is overloaded by subclasses to implement custom logging behaviour. - - @see setCurrentLogger - */ - virtual void logMessage (const String& message) = 0; - -private: - static Logger* currentLogger; -}; - -#endif // __JUCE_LOGGER_JUCEHEADER__ -/*** End of inlined file: juce_Logger.h ***/ - - -/*** Start of inlined file: juce_LeakedObjectDetector.h ***/ -#ifndef __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ -#define __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ - - -/*** Start of inlined file: juce_Atomic.h ***/ -#ifndef __JUCE_ATOMIC_JUCEHEADER__ -#define __JUCE_ATOMIC_JUCEHEADER__ - -/** - Simple class to hold a primitive value and perform atomic operations on it. - - The type used must be a 32 or 64 bit primitive, like an int, pointer, etc. - There are methods to perform most of the basic atomic operations. -*/ -template -class Atomic -{ -public: - /** Creates a new value, initialised to zero. */ - inline Atomic() throw() - : value (0) - { - } - - /** Creates a new value, with a given initial value. */ - inline Atomic (const Type initialValue) throw() - : value (initialValue) - { - } - - /** Copies another value (atomically). */ - inline Atomic (const Atomic& other) throw() - : value (other.get()) - { - } - - /** Destructor. */ - inline ~Atomic() throw() - { - // This class can only be used for types which are 32 or 64 bits in size. - static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8); - } - - /** Atomically reads and returns the current value. */ - Type get() const throw(); - - /** Copies another value onto this one (atomically). */ - inline Atomic& operator= (const Atomic& other) throw() { exchange (other.get()); return *this; } - - /** Copies another value onto this one (atomically). */ - inline Atomic& operator= (const Type newValue) throw() { exchange (newValue); return *this; } - - /** Atomically sets the current value. */ - void set (Type newValue) throw() { exchange (newValue); } - - /** Atomically sets the current value, returning the value that was replaced. */ - Type exchange (Type value) throw(); - - /** Atomically adds a number to this value, returning the new value. */ - Type operator+= (Type amountToAdd) throw(); - - /** Atomically subtracts a number from this value, returning the new value. */ - Type operator-= (Type amountToSubtract) throw(); - - /** Atomically increments this value, returning the new value. */ - Type operator++() throw(); - - /** Atomically decrements this value, returning the new value. */ - Type operator--() throw(); - - /** Atomically compares this value with a target value, and if it is equal, sets - this to be equal to a new value. - - This operation is the atomic equivalent of doing this: - @code - bool compareAndSetBool (Type newValue, Type valueToCompare) - { - if (get() == valueToCompare) - { - set (newValue); - return true; - } - - return false; - } - @endcode - - @returns true if the comparison was true and the value was replaced; false if - the comparison failed and the value was left unchanged. - @see compareAndSetValue - */ - bool compareAndSetBool (Type newValue, Type valueToCompare) throw(); - - /** Atomically compares this value with a target value, and if it is equal, sets - this to be equal to a new value. - - This operation is the atomic equivalent of doing this: - @code - Type compareAndSetValue (Type newValue, Type valueToCompare) - { - Type oldValue = get(); - if (oldValue == valueToCompare) - set (newValue); - - return oldValue; - } - @endcode - - @returns the old value before it was changed. - @see compareAndSetBool - */ - Type compareAndSetValue (Type newValue, Type valueToCompare) throw(); - - /** Implements a memory read/write barrier. */ - static void memoryBarrier() throw(); - - JUCE_ALIGN(8) - - /** The raw value that this class operates on. - This is exposed publically in case you need to manipulate it directly - for performance reasons. - */ - volatile Type value; - -private: - static inline Type castFrom32Bit (int32 value) throw() { return *(Type*) &value; } - static inline Type castFrom64Bit (int64 value) throw() { return *(Type*) &value; } - static inline int32 castTo32Bit (Type value) throw() { return *(int32*) &value; } - static inline int64 castTo64Bit (Type value) throw() { return *(int64*) &value; } - - Type operator++ (int); // better to just use pre-increment with atomics.. - Type operator-- (int); -}; +/** Writes a string to an OutputStream as UTF8. */ +JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& text); -/* - The following code is in the header so that the atomics can be inlined where possible... -*/ -#if (JUCE_IOS && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2 || ! defined (__IPHONE_3_2))) \ - || (JUCE_MAC && (JUCE_PPC || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))) - #define JUCE_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier +#endif // __JUCE_STRING_JUCEHEADER__ +/*** End of inlined file: juce_String.h ***/ - #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - #define JUCE_MAC_ATOMICS_VOLATILE - #else - #define JUCE_MAC_ATOMICS_VOLATILE volatile - #endif +/** + Acts as an application-wide logging class. - #if JUCE_PPC || JUCE_IOS - // None of these atomics are available for PPC or for iPhoneOS 3.1 or earlier!! - template static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return *a += b; } - template static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return ++*a; } - template static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return --*a; } - template static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) throw() - { jassertfalse; if (old == *value) { *value = newValue; return true; } return false; } - #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 - #endif + A subclass of Logger can be created and passed into the Logger::setCurrentLogger + method and this will then be used by all calls to writeToLog. -#elif JUCE_GCC - #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics + The logger class also contains methods for writing messages to the debugger's + output stream. - #if JUCE_IOS - #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 // (on the iphone, the 64-bit ops will compile but not link) - #endif + @see FileLogger +*/ +class JUCE_API Logger +{ +public: -#else - #define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics + /** Destructor. */ + virtual ~Logger(); - #if JUCE_USE_INTRINSICS || JUCE_64BIT - #pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \ - _InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier) - #define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b) - #define juce_InterlockedIncrement(a) _InterlockedIncrement(a) - #define juce_InterlockedDecrement(a) _InterlockedDecrement(a) - #define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b) - #define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c) - #define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c) - #define juce_MemoryBarrier _ReadWriteBarrier - #else - // (these are defined in juce_win32_Threads.cpp) - long juce_InterlockedExchange (volatile long* a, long b) throw(); - long juce_InterlockedIncrement (volatile long* a) throw(); - long juce_InterlockedDecrement (volatile long* a) throw(); - long juce_InterlockedExchangeAdd (volatile long* a, long b) throw(); - long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); - __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw(); - inline void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); } - #endif + /** Sets the current logging class to use. - #if JUCE_64BIT - #pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64) - #define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b) - #define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b) - #define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a) - #define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a) - #else - // None of these atomics are available in a 32-bit Windows build!! - template static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a += b; return old; } - template static Type juce_InterlockedExchange64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a = b; return old; } - template static Type juce_InterlockedIncrement64 (volatile Type* a) throw() { jassertfalse; return ++*a; } - template static Type juce_InterlockedDecrement64 (volatile Type* a) throw() { jassertfalse; return --*a; } - #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 - #endif -#endif + Note that the object passed in won't be deleted when no longer needed. + A null pointer can be passed-in to disable any logging. -#if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4311) // (truncation warning) -#endif + If deleteOldLogger is set to true, the existing logger will be + deleted (if there is one). + */ + static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger, + bool deleteOldLogger = false); -template -inline Type Atomic::get() const throw() -{ - #if JUCE_ATOMICS_MAC - return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)) - : castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value)); - #elif JUCE_ATOMICS_WINDOWS - return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0)) - : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0)); - #elif JUCE_ANDROID - return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (value), castTo32Bit (value), (volatile int*) &value)); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) - : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); - #endif -} + /** Writes a string to the current logger. -template -inline Type Atomic::exchange (const Type newValue) throw() -{ - #if JUCE_ANDROID - return castFrom32Bit (__atomic_swap (castTo32Bit (newValue), (volatile int*) &value)); - #elif JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC - Type currentVal = value; - while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; } - return currentVal; - #elif JUCE_ATOMICS_WINDOWS - return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue))) - : castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue))); - #endif -} + This will pass the string to the logger's logMessage() method if a logger + has been set. -template -inline Type Atomic::operator+= (const Type amountToAdd) throw() -{ - #if JUCE_ATOMICS_MAC - return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) - : (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); - #elif JUCE_ATOMICS_WINDOWS - return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd) - : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd); - #elif JUCE_ANDROID - for (;;) - { - const Type oldValue (value); - const Type newValue (oldValue + amountToAdd); - if (compareAndSetBool (newValue, oldValue)) - return newValue; - } - #elif JUCE_ATOMICS_GCC - return (Type) __sync_add_and_fetch (&value, amountToAdd); - #endif -} + @see logMessage + */ + static void JUCE_CALLTYPE writeToLog (const String& message); -template -inline Type Atomic::operator-= (const Type amountToSubtract) throw() -{ - return operator+= (juce_negate (amountToSubtract)); -} + /** Writes a message to the standard error stream. -template -inline Type Atomic::operator++() throw() -{ - #if JUCE_ATOMICS_MAC - return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) - : (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); - #elif JUCE_ATOMICS_WINDOWS - return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) - : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); - #elif JUCE_ANDROID - return (Type) __atomic_inc (&value); - #elif JUCE_ATOMICS_GCC - return (Type) __sync_add_and_fetch (&value, 1); - #endif -} + This can be called directly, or by using the DBG() macro in + juce_PlatformDefs.h (which will avoid calling the method in non-debug builds). + */ + static void JUCE_CALLTYPE outputDebugString (const String& text); -template -inline Type Atomic::operator--() throw() -{ - #if JUCE_ATOMICS_MAC - return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) - : (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); - #elif JUCE_ATOMICS_WINDOWS - return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) - : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); - #elif JUCE_ANDROID - return (Type) __atomic_dec (&value); - #elif JUCE_ATOMICS_GCC - return (Type) __sync_add_and_fetch (&value, -1); - #endif -} +protected: -template -inline bool Atomic::compareAndSetBool (const Type newValue, const Type valueToCompare) throw() -{ - #if JUCE_ATOMICS_MAC - return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) - : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); - #elif JUCE_ATOMICS_WINDOWS || JUCE_ANDROID - return compareAndSetValue (newValue, valueToCompare) == valueToCompare; - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) - : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); - #endif -} + Logger(); -template -inline Type Atomic::compareAndSetValue (const Type newValue, const Type valueToCompare) throw() -{ - #if JUCE_ATOMICS_MAC - for (;;) // Annoying workaround for OSX only having a bool CAS operation.. - { - if (compareAndSetBool (newValue, valueToCompare)) - return valueToCompare; + /** This is overloaded by subclasses to implement custom logging behaviour. - const Type result = value; - if (result != valueToCompare) - return result; - } + @see setCurrentLogger + */ + virtual void logMessage (const String& message) = 0; - #elif JUCE_ATOMICS_WINDOWS - return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare))) - : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare))); - #elif JUCE_ANDROID - return castFrom32Bit (__atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value)); - #elif JUCE_ATOMICS_GCC - return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) - : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); - #endif -} +private: + static Logger* currentLogger; +}; -template -inline void Atomic::memoryBarrier() throw() -{ - #if JUCE_ATOMICS_MAC - OSMemoryBarrier(); - #elif JUCE_ATOMICS_GCC - __sync_synchronize(); - #elif JUCE_ATOMICS_WINDOWS - juce_MemoryBarrier(); - #endif -} +#endif // __JUCE_LOGGER_JUCEHEADER__ +/*** End of inlined file: juce_Logger.h ***/ -#if JUCE_MSVC - #pragma warning (pop) -#endif -#endif // __JUCE_ATOMIC_JUCEHEADER__ -/*** End of inlined file: juce_Atomic.h ***/ +/*** Start of inlined file: juce_LeakedObjectDetector.h ***/ +#ifndef __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ +#define __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ /** Embedding an instance of this class inside another class can be used as a low-overhead diff --git a/src/audio/audio_file_formats/juce_OggVorbisAudioFormat.cpp b/src/audio/audio_file_formats/juce_OggVorbisAudioFormat.cpp index b6c91cbd1f..0194df9ee9 100644 --- a/src/audio/audio_file_formats/juce_OggVorbisAudioFormat.cpp +++ b/src/audio/audio_file_formats/juce_OggVorbisAudioFormat.cpp @@ -283,7 +283,7 @@ public: vorbis_comment_init (&vc); if (JUCEApplication::getInstance() != 0) - vorbis_comment_add_tag (&vc, "ENCODER", const_cast (JUCEApplication::getInstance()->getApplicationName().toUTF8())); + vorbis_comment_add_tag (&vc, "ENCODER", const_cast (JUCEApplication::getInstance()->getApplicationName().toUTF8().getAddress())); vorbis_analysis_init (&vd, &vi); vorbis_block_init (&vd, &vb); diff --git a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp index 17905977f0..9d84d1fd8e 100644 --- a/src/audio/plugins/formats/juce_VSTPluginFormat.cpp +++ b/src/audio/plugins/formats/juce_VSTPluginFormat.cpp @@ -35,7 +35,10 @@ #define STRICT #include #include - #pragma warning (disable : 4312 4355 1899) + #pragma warning (disable : 4312 4355) + #ifdef __INTEL_COMPILER + #pragma warning (disable : 1899) + #endif #elif JUCE_LINUX #include #include @@ -2321,7 +2324,7 @@ VstIntPtr VSTPluginInstance::handleCallback (VstInt32 opcode, VstInt32 index, Vs #if JUCE_MAC return (VstIntPtr) (void*) &module->parentDirFSSpec; #else - return (VstIntPtr) (pointer_sized_uint) module->fullParentDirectoryPathName.toUTF8(); + return (VstIntPtr) (pointer_sized_uint) module->fullParentDirectoryPathName.toUTF8().getAddress(); #endif case audioMasterGetAutomationState: diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index f83c9e82ad..716edcc45c 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 18 +#define JUCE_BUILDNUMBER 20 /** Current Juce version number. diff --git a/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp b/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp index 0be7cf6524..e691cabf65 100644 --- a/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp +++ b/src/gui/components/code_editor/juce_CPlusPlusCodeTokeniser.cpp @@ -103,7 +103,7 @@ namespace CppTokeniser int i = 0; while (k[i] != 0) { - if (k[i][0] == token[0] && CharPointer_UTF8 (k[i]).compare (CharPointer_UTF32 (token)) == 0) + if (k[i][0] == (char) token[0] && CharPointer_UTF8 (k[i]).compare (CharPointer_UTF32 (token)) == 0) return true; ++i; diff --git a/src/io/network/juce_URL.cpp b/src/io/network/juce_URL.cpp index aa8bd843b5..3c51606d41 100644 --- a/src/io/network/juce_URL.cpp +++ b/src/io/network/juce_URL.cpp @@ -389,7 +389,7 @@ const String URL::removeEscapeChars (const String& s) // We need to operate on the string as raw UTF8 chars, and then recombine them into unicode // after all the replacements have been made, so that multi-byte chars are handled. - Array utf8 (result.toUTF8(), result.getNumBytesAsUTF8()); + Array utf8 (result.toUTF8().getAddress(), result.getNumBytesAsUTF8()); for (int i = 0; i < utf8.size(); ++i) { @@ -414,7 +414,7 @@ const String URL::addEscapeChars (const String& s, const bool isParameter) const CharPointer_UTF8 legalChars (isParameter ? "_-.*!'()" : ",$_-.*!'()"); - Array utf8 (s.toUTF8(), s.getNumBytesAsUTF8()); + Array utf8 (s.toUTF8().getAddress(), s.getNumBytesAsUTF8()); for (int i = 0; i < utf8.size(); ++i) { diff --git a/src/native/linux/juce_linux_Windowing.cpp b/src/native/linux/juce_linux_Windowing.cpp index 7b8c4966ed..3203d75604 100644 --- a/src/native/linux/juce_linux_Windowing.cpp +++ b/src/native/linux/juce_linux_Windowing.cpp @@ -807,7 +807,7 @@ public: void setTitle (const String& title) { XTextProperty nameProperty; - char* strings[] = { const_cast (title.toUTF8()) }; + char* strings[] = { const_cast (title.toUTF8().getAddress()) }; ScopedXLock xlock; if (XStringListToTextProperty (strings, 1, &nameProperty)) diff --git a/src/native/mac/juce_mac_Files.mm b/src/native/mac/juce_mac_Files.mm index cbd1a1f251..2ae784b6e6 100644 --- a/src/native/mac/juce_mac_Files.mm +++ b/src/native/mac/juce_mac_Files.mm @@ -444,7 +444,7 @@ void File::revealToUser() const #if ! JUCE_IOS bool PlatformUtilities::makeFSRefFromPath (FSRef* destFSRef, const String& path) { - return FSPathMakeRef ((const UInt8*) path.toUTF8(), destFSRef, 0) == noErr; + return FSPathMakeRef (reinterpret_cast (path.toUTF8().getAddress()), destFSRef, 0) == noErr; } const String PlatformUtilities::makePathFromFSRef (FSRef* file) diff --git a/src/native/mac/juce_mac_Strings.mm b/src/native/mac/juce_mac_Strings.mm index 1d615dd707..0e7f5cf48b 100644 --- a/src/native/mac/juce_mac_Strings.mm +++ b/src/native/mac/juce_mac_Strings.mm @@ -102,34 +102,25 @@ const String PlatformUtilities::convertToPrecomposedUnicode (const String& s) if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr) { - const int len = s.length(); + const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (s.getCharPointer()); - HeapBlock tempIn, tempOut; - tempIn.calloc (len + 2); - tempOut.calloc (len + 2); - - for (int i = 0; i <= len; ++i) - tempIn[i] = s[i]; + HeapBlock tempOut; + tempOut.calloc (bytesNeeded + 4); ByteCount bytesRead = 0; ByteCount outputBufferSize = 0; if (ConvertFromUnicodeToText (conversionInfo, - len * sizeof (UniChar), tempIn, + bytesNeeded, (ConstUniCharArrayPtr) s.toUTF16().getAddress(), kUnicodeDefaultDirectionMask, 0, 0, 0, 0, - len * sizeof (UniChar), &bytesRead, + bytesNeeded, &bytesRead, &outputBufferSize, tempOut) == noErr) { result.preallocateStorage (bytesRead / sizeof (UniChar) + 2); - juce_wchar* t = result; - - unsigned int i; - for (i = 0; i < bytesRead / sizeof (UniChar); ++i) - t[i] = (juce_wchar) tempOut[i]; - - t[i] = 0; + CharPointer_UTF32 dest (static_cast (result)); + dest.writeAll (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData())); } DisposeUnicodeToTextInfo (&conversionInfo); diff --git a/src/native/windows/juce_win32_DynamicLibraryLoader.cpp b/src/native/windows/juce_win32_DynamicLibraryLoader.cpp index 0a35a6d66b..bfb45e70f8 100644 --- a/src/native/windows/juce_win32_DynamicLibraryLoader.cpp +++ b/src/native/windows/juce_win32_DynamicLibraryLoader.cpp @@ -44,13 +44,13 @@ DynamicLibraryLoader::~DynamicLibraryLoader() bool DynamicLibraryLoader::load (const String& name) { FreeLibrary ((HMODULE) libHandle); - libHandle = name.isNotEmpty() ? LoadLibrary (name) : 0; + libHandle = name.isNotEmpty() ? LoadLibrary (name.toUTF16()) : 0; return libHandle != 0; } void* DynamicLibraryLoader::findProcAddress (const String& functionName) { - return (void*) GetProcAddress ((HMODULE) libHandle, functionName.toCString()); // (void* cast is required for mingw) + return (void*) GetProcAddress ((HMODULE) libHandle, functionName.toUTF8()); // (void* cast is required for mingw) } #endif diff --git a/src/native/windows/juce_win32_FileChooser.cpp b/src/native/windows/juce_win32_FileChooser.cpp index 5720f7cae6..a6f8ffef21 100644 --- a/src/native/windows/juce_win32_FileChooser.cpp +++ b/src/native/windows/juce_win32_FileChooser.cpp @@ -56,7 +56,7 @@ namespace FileChooserHelpers FileChooserCallbackInfo* info = (FileChooserCallbackInfo*) lpData; if (msg == BFFM_INITIALIZED) - SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) static_cast (info->initialPath)); + SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) info->initialPath.toUTF16().getAddress()); else if (msg == BFFM_VALIDATEFAILEDW) info->returnedString = (LPCWSTR) lParam; else if (msg == BFFM_VALIDATEFAILEDA) @@ -174,7 +174,7 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, } else { - currentFileOrDirectory.getFileName().copyToUnicode (files, charsAvailableForResult); + currentFileOrDirectory.getFileName().copyToUTF16 (files, charsAvailableForResult * sizeof (WCHAR)); info.initialPath = currentFileOrDirectory.getParentDirectory().getFullPathName(); } @@ -185,7 +185,7 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, bi.hwndOwner = (HWND) parentWindow.getWindowHandle(); bi.pszDisplayName = files; - bi.lpszTitle = title; + bi.lpszTitle = title.toUTF16(); bi.lParam = (LPARAM) &info; bi.lpfn = browseCallbackProc; #ifdef BIF_USENEWUI @@ -230,10 +230,11 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, info.customComponent->enterModalState(); } - WCHAR filters [1024]; - zerostruct (filters); - filter.copyToUnicode (filters, 1024); - filter.copyToUnicode (filters + filter.length() + 1, 1022 - filter.length()); + const int filterSpace = 2048; + HeapBlock filters; + filters.calloc (filterSpace * 2); + const int bytesWritten = filter.copyToUTF16 (reinterpret_cast (filters.getData()), filterSpace); + filter.copyToUTF16 (reinterpret_cast (filters + bytesWritten), filterSpace); OPENFILENAMEW of; zerostruct (of); @@ -244,12 +245,12 @@ void FileChooser::showPlatformDialog (Array& results, const String& title, of.lStructSize = sizeof (of); #endif of.hwndOwner = (HWND) parentWindow.getWindowHandle(); - of.lpstrFilter = filters; + of.lpstrFilter = reinterpret_cast (filters.getData()); of.nFilterIndex = 1; of.lpstrFile = files; of.nMaxFile = charsAvailableForResult; - of.lpstrInitialDir = info.initialPath; - of.lpstrTitle = title; + of.lpstrInitialDir = info.initialPath.toUTF16(); + of.lpstrTitle = title.toUTF16(); of.Flags = flags; of.lCustData = (LPARAM) &info; diff --git a/src/native/windows/juce_win32_Files.cpp b/src/native/windows/juce_win32_Files.cpp index 1b0e342353..49a99c37b3 100644 --- a/src/native/windows/juce_win32_Files.cpp +++ b/src/native/windows/juce_win32_Files.cpp @@ -56,14 +56,12 @@ namespace WindowsFileHelpers reinterpret_cast (ft)->QuadPart = time * 10000 + literal64bit (116444736000000000); } - const String getDriveFromPath (const String& path) + const String getDriveFromPath (String path) { - const int length = path.length(); - HeapBlock stringCopy (length + 1); - path.copyToUnicode (stringCopy, length); + WCHAR* p = const_cast (path.toUTF16().getAddress()); - if (PathStripToRoot (stringCopy)) - return String (stringCopy); + if (PathStripToRoot (p)) + return String ((const WCHAR*) p); return path; } @@ -72,7 +70,7 @@ namespace WindowsFileHelpers { ULARGE_INTEGER spc, tot, totFree; - if (GetDiskFreeSpaceEx (getDriveFromPath (path), &spc, &tot, &totFree)) + if (GetDiskFreeSpaceEx (getDriveFromPath (path).toUTF16(), &spc, &tot, &totFree)) return total ? (int64) tot.QuadPart : (int64) spc.QuadPart; @@ -81,7 +79,7 @@ namespace WindowsFileHelpers unsigned int getWindowsDriveType (const String& path) { - return GetDriveType (getDriveFromPath (path)); + return GetDriveType (getDriveFromPath (path).toUTF16()); } const File getSpecialFolderPath (int type) @@ -104,25 +102,25 @@ const String File::separatorString ("\\"); bool File::exists() const { return fullPath.isNotEmpty() - && GetFileAttributes (fullPath) != INVALID_FILE_ATTRIBUTES; + && GetFileAttributes (fullPath.toUTF16()) != INVALID_FILE_ATTRIBUTES; } bool File::existsAsFile() const { return fullPath.isNotEmpty() - && (GetFileAttributes (fullPath) & FILE_ATTRIBUTE_DIRECTORY) == 0; + && (GetFileAttributes (fullPath.toUTF16()) & FILE_ATTRIBUTE_DIRECTORY) == 0; } bool File::isDirectory() const { - const DWORD attr = GetFileAttributes (fullPath); + const DWORD attr = GetFileAttributes (fullPath.toUTF16()); return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) && (attr != INVALID_FILE_ATTRIBUTES); } bool File::hasWriteAccess() const { if (exists()) - return (GetFileAttributes (fullPath) & FILE_ATTRIBUTE_READONLY) == 0; + return (GetFileAttributes (fullPath.toUTF16()) & FILE_ATTRIBUTE_READONLY) == 0; // on windows, it seems that even read-only directories can still be written into, // so checking the parent directory's permissions would return the wrong result.. @@ -131,7 +129,7 @@ bool File::hasWriteAccess() const bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const { - DWORD attr = GetFileAttributes (fullPath); + DWORD attr = GetFileAttributes (fullPath.toUTF16()); if (attr == INVALID_FILE_ATTRIBUTES) return false; @@ -144,12 +142,12 @@ bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const else attr &= ~FILE_ATTRIBUTE_READONLY; - return SetFileAttributes (fullPath, attr) != FALSE; + return SetFileAttributes (fullPath.toUTF16(), attr) != FALSE; } bool File::isHidden() const { - return (GetFileAttributes (getFullPathName()) & FILE_ATTRIBUTE_HIDDEN) != 0; + return (GetFileAttributes (getFullPathName().toUTF16()) & FILE_ATTRIBUTE_HIDDEN) != 0; } //============================================================================== @@ -158,9 +156,9 @@ bool File::deleteFile() const if (! exists()) return true; else if (isDirectory()) - return RemoveDirectory (fullPath) != 0; + return RemoveDirectory (fullPath.toUTF16()) != 0; else - return DeleteFile (fullPath) != 0; + return DeleteFile (fullPath.toUTF16()) != 0; } bool File::moveToTrash() const @@ -173,7 +171,7 @@ bool File::moveToTrash() const // The string we pass in must be double null terminated.. String doubleNullTermPath (getFullPathName() + " "); - TCHAR* const p = const_cast (static_cast (doubleNullTermPath)); + WCHAR* const p = const_cast (doubleNullTermPath.toUTF16().getAddress()); p [getFullPathName().length()] = 0; fos.wFunc = FO_DELETE; @@ -186,17 +184,17 @@ bool File::moveToTrash() const bool File::copyInternal (const File& dest) const { - return CopyFile (fullPath, dest.getFullPathName(), false) != 0; + return CopyFile (fullPath.toUTF16(), dest.getFullPathName().toUTF16(), false) != 0; } bool File::moveInternal (const File& dest) const { - return MoveFile (fullPath, dest.getFullPathName()) != 0; + return MoveFile (fullPath.toUTF16(), dest.getFullPathName().toUTF16()) != 0; } void File::createDirectoryInternal (const String& fileName) const { - CreateDirectory (fileName, 0); + CreateDirectory (fileName.toUTF16(), 0); } //============================================================================== @@ -212,7 +210,7 @@ void FileInputStream::openHandle() { totalSize = file.getSize(); - HANDLE h = CreateFile (file.getFullPathName(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + HANDLE h = CreateFile (file.getFullPathName().toUTF16(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0); if (h != INVALID_HANDLE_VALUE) @@ -239,7 +237,7 @@ size_t FileInputStream::readInternal (void* buffer, size_t numBytes) //============================================================================== void FileOutputStream::openHandle() { - HANDLE h = CreateFile (file.getFullPathName(), GENERIC_WRITE, FILE_SHARE_READ, 0, + HANDLE h = CreateFile (file.getFullPathName().toUTF16(), GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (h != INVALID_HANDLE_VALUE) @@ -284,7 +282,7 @@ int64 File::getSize() const { WIN32_FILE_ATTRIBUTE_DATA attributes; - if (GetFileAttributesEx (fullPath, GetFileExInfoStandard, &attributes)) + if (GetFileAttributesEx (fullPath.toUTF16(), GetFileExInfoStandard, &attributes)) return (((int64) attributes.nFileSizeHigh) << 32) | attributes.nFileSizeLow; return 0; @@ -295,7 +293,7 @@ void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int using namespace WindowsFileHelpers; WIN32_FILE_ATTRIBUTE_DATA attributes; - if (GetFileAttributesEx (fullPath, GetFileExInfoStandard, &attributes)) + if (GetFileAttributesEx (fullPath.toUTF16(), GetFileExInfoStandard, &attributes)) { modificationTime = fileTimeToTime (&attributes.ftLastWriteTime); creationTime = fileTimeToTime (&attributes.ftCreationTime); @@ -312,7 +310,7 @@ bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 using namespace WindowsFileHelpers; bool ok = false; - HANDLE h = CreateFile (fullPath, GENERIC_WRITE, FILE_SHARE_READ, 0, + HANDLE h = CreateFile (fullPath.toUTF16(), GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (h != INVALID_HANDLE_VALUE) @@ -362,7 +360,7 @@ void File::findFileSystemRoots (Array& destArray) const String File::getVolumeLabel() const { TCHAR dest[64]; - if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()), dest, + if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toUTF16(), dest, numElementsInArray (dest), 0, 0, 0, 0, 0)) dest[0] = 0; @@ -374,7 +372,7 @@ int File::getVolumeSerialNumber() const TCHAR dest[64]; DWORD serialNum; - if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()), dest, + if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toUTF16(), dest, numElementsInArray (dest), &serialNum, 0, 0, 0, 0)) return 0; @@ -486,7 +484,7 @@ const File File::getCurrentWorkingDirectory() bool File::setAsCurrentWorkingDirectory() const { - return SetCurrentDirectory (getFullPathName()) != FALSE; + return SetCurrentDirectory (getFullPathName().toUTF16()) != FALSE; } //============================================================================== @@ -495,11 +493,11 @@ const String File::getVersion() const String result; DWORD handle = 0; - DWORD bufferSize = GetFileVersionInfoSize (getFullPathName(), &handle); + DWORD bufferSize = GetFileVersionInfoSize (getFullPathName().toUTF16(), &handle); HeapBlock buffer; buffer.calloc (bufferSize); - if (GetFileVersionInfo (getFullPathName(), 0, bufferSize, buffer)) + if (GetFileVersionInfo (getFullPathName().toUTF16(), 0, bufferSize, buffer)) { VS_FIXEDFILEINFO* vffi; UINT len = 0; @@ -533,7 +531,7 @@ const File File::getLinkedTarget() const ComSmartPtr persistFile; if (SUCCEEDED (shellLink.QueryInterface (IID_IPersistFile, persistFile))) { - if (SUCCEEDED (persistFile->Load ((const WCHAR*) p, STGM_READ)) + if (SUCCEEDED (persistFile->Load (p.toUTF16(), STGM_READ)) && SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI))) { WIN32_FIND_DATA winFindData; @@ -574,7 +572,7 @@ public: if (handle == INVALID_HANDLE_VALUE) { - handle = FindFirstFile (directoryWithWildCard, &findData); + handle = FindFirstFile (directoryWithWildCard.toUTF16(), &findData); if (handle == INVALID_HANDLE_VALUE) return false; @@ -628,7 +626,7 @@ bool PlatformUtilities::openDocument (const String& fileName, const String& para JUCE_TRY { - hInstance = ShellExecute (0, 0, fileName, parameters, 0, SW_SHOWDEFAULT); + hInstance = ShellExecute (0, 0, fileName.toUTF16(), parameters.toUTF16(), 0, SW_SHOWDEFAULT); } JUCE_CATCH_ALL @@ -655,9 +653,9 @@ public: { cancelEvent = CreateEvent (0, FALSE, FALSE, 0); - pipeH = isPipe ? CreateNamedPipe (file, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, + pipeH = isPipe ? CreateNamedPipe (file.toUTF16(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0, PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0) - : CreateFile (file, GENERIC_READ | GENERIC_WRITE, 0, 0, + : CreateFile (file.toUTF16(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); } diff --git a/src/native/windows/juce_win32_Fonts.cpp b/src/native/windows/juce_win32_Fonts.cpp index d73cd99528..34fb027338 100644 --- a/src/native/windows/juce_win32_Fonts.cpp +++ b/src/native/windows/juce_win32_Fonts.cpp @@ -62,7 +62,7 @@ static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe, lf.lfPitchAndFamily = FF_DONTCARE; const String fontName (lpelfe->elfLogFont.lfFaceName); - fontName.copyToUnicode (lf.lfFaceName, LF_FACESIZE - 1); + fontName.copyToUTF16 (lf.lfFaceName, LF_FACESIZE - 1); HDC dc = CreateCompatibleDC (0); EnumFontFamiliesEx (dc, &lf, @@ -168,7 +168,7 @@ public: lfw.lfQuality = PROOF_QUALITY; lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE); lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL; - fontName.copyToUnicode (lfw.lfFaceName, LF_FACESIZE - 1); + fontName.copyToUTF16 (lfw.lfFaceName, LF_FACESIZE - 1); lfw.lfHeight = size > 0 ? size : -256; HFONT standardSizedFont = CreateFontIndirect (&lfw); diff --git a/src/native/windows/juce_win32_Messaging.cpp b/src/native/windows/juce_win32_Messaging.cpp index 964b8c7a69..cb92d9af9a 100644 --- a/src/native/windows/juce_win32_Messaging.cpp +++ b/src/native/windows/juce_win32_Messaging.cpp @@ -285,7 +285,7 @@ void MessageManager::doPlatformSpecificInitialisation() wc.lpfnWndProc = (WNDPROC) juce_MessageWndProc; wc.cbWndExtra = 4; wc.hInstance = hmod; - wc.lpszClassName = className; + wc.lpszClassName = className.toUTF16(); RegisterClassEx (&wc); @@ -298,7 +298,7 @@ void MessageManager::doPlatformSpecificInitialisation() void MessageManager::doPlatformSpecificShutdown() { DestroyWindow (juce_messageWindowHandle); - UnregisterClass (getMessageWindowClassName(), 0); + UnregisterClass (getMessageWindowClassName().toUTF16(), 0); OleUninitialize(); } diff --git a/src/native/windows/juce_win32_Misc.cpp b/src/native/windows/juce_win32_Misc.cpp index d113738859..90966329e6 100644 --- a/src/native/windows/juce_win32_Misc.cpp +++ b/src/native/windows/juce_win32_Misc.cpp @@ -35,17 +35,16 @@ void SystemClipboard::copyTextToClipboard (const String& text) { if (EmptyClipboard() != 0) { - const int len = text.length(); + const int bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer()); - if (len > 0) + if (bytesNeeded > 0) { - HGLOBAL bufH = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, - (len + 1) * sizeof (wchar_t)); + HGLOBAL bufH = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, bytesNeeded + sizeof (WCHAR)); if (bufH != 0) { WCHAR* const data = static_cast (GlobalLock (bufH)); - text.copyToUnicode (data, len); + text.copyToUTF16 (data, bytesNeeded); GlobalUnlock (bufH); SetClipboardData (CF_UNICODETEXT, bufH); diff --git a/src/native/windows/juce_win32_Network.cpp b/src/native/windows/juce_win32_Network.cpp index a3bd584351..6fbaaaccc6 100644 --- a/src/native/windows/juce_win32_Network.cpp +++ b/src/native/windows/juce_win32_Network.cpp @@ -235,7 +235,7 @@ private: uc.lpszUrlPath = file; uc.lpszHostName = server; - if (InternetCrackUrl (address, 0, 0, &uc)) + if (InternetCrackUrl (address.toUTF16(), 0, 0, &uc)) { int disable = 1; InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable)); @@ -295,7 +295,7 @@ private: INTERNET_BUFFERS buffers; zerostruct (buffers); buffers.dwStructSize = sizeof (INTERNET_BUFFERS); - buffers.lpcszHeader = static_cast (headers); + buffers.lpcszHeader = headers.toUTF16(); buffers.dwHeadersLength = headers.length(); buffers.dwBufferTotal = (DWORD) postData.getSize(); diff --git a/src/native/windows/juce_win32_PlatformUtils.cpp b/src/native/windows/juce_win32_PlatformUtils.cpp index 86ec069995..795998913f 100644 --- a/src/native/windows/juce_win32_PlatformUtils.cpp +++ b/src/native/windows/juce_win32_PlatformUtils.cpp @@ -55,13 +55,13 @@ namespace if (createForWriting) { - if (RegCreateKeyEx (rootKey, name, 0, 0, REG_OPTION_NON_VOLATILE, + if (RegCreateKeyEx (rootKey, name.toUTF16(), 0, 0, REG_OPTION_NON_VOLATILE, (KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result) == ERROR_SUCCESS) return key; } else { - if (RegOpenKeyEx (rootKey, name, 0, KEY_READ, &key) == ERROR_SUCCESS) + if (RegOpenKeyEx (rootKey, name.toUTF16(), 0, KEY_READ, &key) == ERROR_SUCCESS) return key; } } @@ -82,7 +82,7 @@ const String PlatformUtilities::getRegistryValue (const String& regValuePath, unsigned long bufferSize = sizeof (buffer); DWORD type = REG_SZ; - if (RegQueryValueEx (k, valueName, 0, &type, (LPBYTE) buffer, &bufferSize) == ERROR_SUCCESS) + if (RegQueryValueEx (k, valueName.toUTF16(), 0, &type, (LPBYTE) buffer, &bufferSize) == ERROR_SUCCESS) { if (type == REG_SZ) result = buffer; @@ -104,9 +104,9 @@ void PlatformUtilities::setRegistryValue (const String& regValuePath, if (k != 0) { - RegSetValueEx (k, valueName, 0, REG_SZ, - (const BYTE*) (const WCHAR*) value, - sizeof (WCHAR) * (value.length() + 1)); + RegSetValueEx (k, valueName.toUTF16(), 0, REG_SZ, + (const BYTE*) value.toUTF16().getAddress(), + CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer())); RegCloseKey (k); } @@ -124,7 +124,7 @@ bool PlatformUtilities::registryValueExists (const String& regValuePath) unsigned long bufferSize = sizeof (buffer); DWORD type = 0; - if (RegQueryValueEx (k, valueName, 0, &type, buffer, &bufferSize) == ERROR_SUCCESS) + if (RegQueryValueEx (k, valueName.toUTF16(), 0, &type, buffer, &bufferSize) == ERROR_SUCCESS) exists = true; RegCloseKey (k); @@ -140,7 +140,7 @@ void PlatformUtilities::deleteRegistryValue (const String& regValuePath) if (k != 0) { - RegDeleteValue (k, valueName); + RegDeleteValue (k, valueName.toUTF16()); RegCloseKey (k); } } @@ -152,7 +152,7 @@ void PlatformUtilities::deleteRegistryKey (const String& regKeyPath) if (k != 0) { - RegDeleteKey (k, valueName); + RegDeleteKey (k, valueName.toUTF16()); RegCloseKey (k); } } diff --git a/src/native/windows/juce_win32_SystemStats.cpp b/src/native/windows/juce_win32_SystemStats.cpp index 3e41e1d779..4b365894aa 100644 --- a/src/native/windows/juce_win32_SystemStats.cpp +++ b/src/native/windows/juce_win32_SystemStats.cpp @@ -31,7 +31,7 @@ //============================================================================== void Logger::outputDebugString (const String& text) { - OutputDebugString (text + "\n"); + OutputDebugString ((text + "\n").toUTF16()); } //============================================================================== diff --git a/src/native/windows/juce_win32_Threads.cpp b/src/native/windows/juce_win32_Threads.cpp index 3d1f11fdf1..633e83bd7a 100644 --- a/src/native/windows/juce_win32_Threads.cpp +++ b/src/native/windows/juce_win32_Threads.cpp @@ -318,7 +318,7 @@ void* PlatformUtilities::loadDynamicLibrary (const String& name) JUCE_TRY { - result = LoadLibrary (name); + result = LoadLibrary (name.toUTF16()); } JUCE_CATCH_ALL @@ -348,7 +348,7 @@ public: Pimpl (const String& name, const int timeOutMillisecs) : handle (0), refCount (1) { - handle = CreateMutex (0, TRUE, "Global\\" + name.replaceCharacter ('\\','/')); + handle = CreateMutex (0, TRUE, ("Global\\" + name.replaceCharacter ('\\','/')).toUTF16()); if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS) { diff --git a/src/native/windows/juce_win32_WebBrowserComponent.cpp b/src/native/windows/juce_win32_WebBrowserComponent.cpp index 9b87474173..cea5d75cd9 100644 --- a/src/native/windows/juce_win32_WebBrowserComponent.cpp +++ b/src/native/windows/juce_win32_WebBrowserComponent.cpp @@ -90,7 +90,7 @@ public: if (headers != 0) { V_VT (&headersVar) = VT_BSTR; - V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n")); + V_BSTR (&headersVar) = SysAllocString ((const OLECHAR*) headers->joinIntoString ("\r\n").toUTF16().getAddress()); } if (postData != 0 && postData->getSize() > 0) @@ -118,7 +118,7 @@ public: } } - browser->Navigate ((BSTR) (const OLECHAR*) url, + browser->Navigate ((BSTR) (const OLECHAR*) url.toUTF16().getAddress(), &flags, &frame, &postDataVar, &headersVar); diff --git a/src/native/windows/juce_win32_Windowing.cpp b/src/native/windows/juce_win32_Windowing.cpp index b12937ed84..95cb724eee 100644 --- a/src/native/windows/juce_win32_Windowing.cpp +++ b/src/native/windows/juce_win32_Windowing.cpp @@ -536,7 +536,7 @@ public: void setTitle (const String& title) { - SetWindowText (hwnd, title); + SetWindowText (hwnd, title.toUTF16()); } void setPosition (int x, int y) @@ -900,7 +900,7 @@ public: if (taskBarIcon != 0) { taskBarIcon->uFlags = NIF_TIP; - toolTip.copyToUnicode (taskBarIcon->szTip, sizeof (taskBarIcon->szTip) - 1); + toolTip.copyToUTF16 (taskBarIcon->szTip, sizeof (taskBarIcon->szTip) - 1); Shell_NotifyIcon (NIM_MODIFY, taskBarIcon); } } @@ -1076,7 +1076,7 @@ private: wcex.cbSize = sizeof (wcex); wcex.style = CS_OWNDC; wcex.lpfnWndProc = (WNDPROC) windowProc; - wcex.lpszClassName = windowClassName; + wcex.lpszClassName = windowClassName.toUTF16(); wcex.cbClsExtra = 0; wcex.cbWndExtra = 32; wcex.hInstance = moduleHandle; @@ -1093,7 +1093,7 @@ private: ~WindowClassHolder() { if (ComponentPeer::getNumPeers() == 0) - UnregisterClass (windowClassName, (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle()); + UnregisterClass (windowClassName.toUTF16(), (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle()); clearSingletonInstance(); } @@ -1159,7 +1159,7 @@ private: && Desktop::canUseSemiTransparentWindows()) exstyle |= WS_EX_LAYERED; - hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->windowClassName, L"", type, 0, 0, 0, 0, + hwnd = CreateWindowEx (exstyle, WindowClassHolder::getInstance()->windowClassName.toUTF16(), L"", type, 0, 0, 0, 0, parentToAddTo, 0, (HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), 0); #if JUCE_DIRECT2D @@ -2436,7 +2436,7 @@ bool AlertWindow::showNativeDialogBox (const String& title, const String& bodyText, bool isOkCancel) { - return MessageBox (0, bodyText, title, + return MessageBox (0, bodyText.toUTF16(), title.toUTF16(), MB_SETFOREGROUND | (isOkCancel ? MB_OKCANCEL : MB_OK)) == IDOK; } @@ -2587,13 +2587,10 @@ void juce_updateMultiMonitorInfo (Array >& monitorCoords, const const Image juce_createIconForFile (const File& file) { Image image; - - WCHAR filename [1024]; - file.getFullPathName().copyToUnicode (filename, 1023); WORD iconNum = 0; HICON icon = ExtractAssociatedIcon ((HINSTANCE) PlatformUtilities::getCurrentModuleInstanceHandle(), - filename, &iconNum); + const_cast (file.getFullPathName().toUTF16().getAddress()), &iconNum); if (icon != 0) { @@ -2908,12 +2905,11 @@ private: static HDROP createHDrop (const StringArray& fileNames) { - int totalChars = 0; + int totalBytes = 0; for (int i = fileNames.size(); --i >= 0;) - totalChars += fileNames[i].length() + 1; + totalBytes += CharPointer_UTF16::getBytesRequiredFor (fileNames[i].getCharPointer()) + sizeof (WCHAR); - HDROP hDrop = (HDROP) GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, - sizeof (DROPFILES) + sizeof (WCHAR) * (totalChars + 2)); + HDROP hDrop = (HDROP) GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (DROPFILES) + totalBytes + 4); if (hDrop != 0) { @@ -2925,8 +2921,8 @@ static HDROP createHDrop (const StringArray& fileNames) for (int i = 0; i < fileNames.size(); ++i) { - fileNames[i].copyToUnicode (fname, 2048); - fname += fileNames[i].length() + 1; + const int bytesWritten = fileNames[i].copyToUTF16 (fname, 2048); + fname = reinterpret_cast (addBytesToPointer (fname, bytesWritten)); } *fname = 0; @@ -2967,12 +2963,12 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text) FORMATETC format = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM medium = { TYMED_HGLOBAL, { 0 }, 0 }; - const int numChars = text.length(); + const int numBytes = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer()); - medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, (numChars + 2) * sizeof (WCHAR)); + medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, numBytes + 2); WCHAR* const data = static_cast (GlobalLock (medium.hGlobal)); - text.copyToUnicode (data, numChars + 1); + text.copyToUTF16 (data, numBytes); format.cfFormat = CF_UNICODETEXT; GlobalUnlock (medium.hGlobal); diff --git a/src/text/juce_CharPointer_UTF16.h b/src/text/juce_CharPointer_UTF16.h index 75181f588d..db7f2c3865 100644 --- a/src/text/juce_CharPointer_UTF16.h +++ b/src/text/juce_CharPointer_UTF16.h @@ -36,9 +36,13 @@ class CharPointer_UTF16 { public: + #if JUCE_WINDOWS && ! DOXYGEN + typedef wchar_t CharType; + #else typedef int16 CharType; + #endif - inline CharPointer_UTF16 (const CharType* const rawPointer) throw() + inline explicit CharPointer_UTF16 (const CharType* const rawPointer) throw() : data (const_cast (rawPointer)) { } @@ -54,19 +58,40 @@ public: return *this; } + inline CharPointer_UTF16& 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_UTF16& other) const throw() + { + return data == other.data; + } + + /** This is a pointer comparison, it doesn't compare the actual text. */ + inline bool operator!= (const CharPointer_UTF16& other) const throw() + { + return data == other.data; + } + /** Returns the address that this pointer is pointing to. */ - inline CharType* getAddress() const throw() { return data; } + 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; } + inline bool isEmpty() const throw() { return *data == 0; } /** Returns the unicode character that this pointer is pointing to. */ juce_wchar operator*() const throw() { uint32 n = (uint32) (uint16) *data; - if (n >= 0xd800 && n <= 0xdfff) - n = 0x10000 + (((n & ~0xd800) << 10) | (data[1] & ~0xdc00)); + if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) data[1]) >= 0xdc00) + n = 0x10000 + (((n - 0xd800) << 10) | (((uint32) (uint16) data[1]) - 0xdc00)); return (juce_wchar) n; } @@ -76,7 +101,7 @@ public: { const juce_wchar n = *data++; - if (n >= 0xd800 && n <= 0xdfff) + if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00) ++data; return *this; @@ -88,11 +113,8 @@ public: { uint32 n = (uint32) (uint16) *data++; - if (n >= 0xd800 && n <= 0xdfff) - { - n = 0x10000 + (((n & ~0xd800) << 10) | (*data & ~0xdc00)); - ++data; - } + if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00) + n = 0x10000 + ((((n - 0xd800) << 10) | (((uint32) (uint16) *data++) - 0xdc00))); return (juce_wchar) n; } @@ -115,7 +137,7 @@ public: } /** Returns the character at a given character index from the start of the string. */ - juce_wchar operator[] (int characterIndex) const throw() + juce_wchar operator[] (const int characterIndex) const throw() { CharPointer_UTF16 p (*this); p += characterIndex; @@ -123,7 +145,7 @@ public: } /** Returns a pointer which is moved forwards from this one by the specified number of characters. */ - CharPointer_UTF16 operator+ (int numToSkip) const throw() + CharPointer_UTF16 operator+ (const int numToSkip) const throw() { CharPointer_UTF16 p (*this); p += numToSkip; @@ -131,19 +153,26 @@ public: } /** Writes a unicode character to this string, and advances this pointer to point to the next position. */ - void write (const juce_wchar charToWrite) throw() + void write (juce_wchar charToWrite) throw() { - if (charToWrite < 0xd800 || (charToWrite > 0xdfff && charToWrite <= 0xffff)) + if (charToWrite >= 0x10000) { - *data++ = (CharType) charToWrite; + charToWrite -= 0x10000; + *data++ = (CharType) (0xd800 + (charToWrite >> 10)); + *data++ = (CharType) (0xdc00 + (charToWrite & 0x3ff)); } else { - *data++ = (CharType) ((0xd800 - (0x10000 >> 10)) + (charToWrite >> 10)); - *data++ = (CharType) (0xdc00 + (charToWrite & 0x3ff)); + *data++ = (CharType) charToWrite; } } + /** 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() { @@ -155,7 +184,10 @@ public: const int n = *d++; if (n >= 0xd800 && n <= 0xdfff) - ++d; + { + if (*d++ == 0) + break; + } else if (n == 0) break; @@ -165,6 +197,12 @@ public: return count; } + /** 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. */ @@ -178,8 +216,7 @@ public: */ static size_t getBytesRequiredFor (const juce_wchar charToWrite) throw() { - return (charToWrite < 0xd800 || (charToWrite > 0xdfff && charToWrite <= 0xffff)) - ? 1 : 2; + return (charToWrite >= 0x10000) ? (sizeof (CharType) * 2) : sizeof (CharType); } /** Returns the number of bytes that would be needed to represent the given @@ -211,13 +248,13 @@ public: /** Copies a source string to this pointer, advancing this pointer as it goes. */ template - void copyAndAdvance (const CharPointer& src) throw() + void writeAll (const CharPointer& src) throw() { - CharacterFunctions::copyAndAdvance (*this, src); + CharacterFunctions::copyAll (*this, src); } /** Copies a source string to this pointer, advancing this pointer as it goes. */ - void copyAndAdvance (const CharPointer_UTF16& src) throw() + void writeAll (const CharPointer_UTF16& src) throw() { const CharType* s = src.data; @@ -229,13 +266,13 @@ public: } /** Copies a source string to this pointer, advancing this pointer as it goes. - The maxBytes parameter specifies the maximum number of bytes that can be written + The maxDestBytes parameter specifies the maximum number of bytes that can be written to the destination buffer before stopping. */ template - int copyAndAdvanceUpToBytes (const CharPointer& src, int maxBytes) throw() + int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw() { - return CharacterFunctions::copyAndAdvanceUpToBytes (*this, src, maxBytes); + return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes); } /** Copies a source string to this pointer, advancing this pointer as it goes. @@ -243,9 +280,9 @@ public: written to the destination buffer before stopping (including the terminating null). */ template - void copyAndAdvanceUpToNumChars (const CharPointer& src, int maxChars) throw() + void writeWithCharLimit (const CharPointer& src, const int maxChars) throw() { - CharacterFunctions::copyAndAdvanceUpToNumChars (*this, src, maxChars); + CharacterFunctions::copyWithCharLimit (*this, src, maxChars); } /** Compares this string with another one. */ @@ -257,7 +294,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareUpTo (const CharPointer& other, int maxChars) const throw() + int compareUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareUpTo (*this, other, maxChars); } @@ -271,11 +308,29 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareIgnoreCaseUpTo (const CharPointer& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); } + #if JUCE_WINDOWS && ! DOXYGEN + int compareIgnoreCase (const CharPointer_UTF16& other) const throw() + { + return _wcsicmp (data, other.data); + } + + int compareIgnoreCaseUpTo (const CharPointer_UTF16& other, int maxChars) const throw() + { + return _wcsnicmp (data, other.data, maxChars); + } + + int indexOf (const CharPointer_UTF16& stringToFind) const throw() + { + const CharType* const t = wcsstr (data, stringToFind.getAddress()); + return t == 0 ? -1 : (int) (t - data); + } + #endif + /** Returns the character index of a substring, or -1 if it isn't found. */ template int indexOf (const CharPointer& stringToFind) const throw() @@ -315,9 +370,24 @@ public: juce_wchar toLowerCase() const throw() { return CharacterFunctions::toLowerCase (operator*()); } /** Parses this string as a 32-bit integer. */ - int getIntValue32() const throw() { return CharacterFunctions::getIntValue (*this); } + int getIntValue32() const throw() + { + #if JUCE_WINDOWS + return _wtoi (data); + #else + return CharacterFunctions::getIntValue (*this); + #endif + } + /** Parses this string as a 64-bit integer. */ - int64 getIntValue64() const throw() { return CharacterFunctions::getIntValue (*this); } + int64 getIntValue64() const throw() + { + #if JUCE_WINDOWS + return _wtoi64 (data); + #else + return CharacterFunctions::getIntValue (*this); + #endif + } /** Parses this string as a floating point double. */ double getDoubleValue() const throw() { return CharacterFunctions::getDoubleValue (*this); } @@ -325,6 +395,15 @@ public: /** Returns the first non-whitespace character in the string. */ CharPointer_UTF16 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); } + /** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */ + enum + { + byteOrderMarkBE1 = 0xfe, + byteOrderMarkBE2 = 0xff, + byteOrderMarkLE1 = 0xff, + byteOrderMarkLE2 = 0xfe + }; + private: CharType* data; diff --git a/src/text/juce_CharPointer_UTF32.h b/src/text/juce_CharPointer_UTF32.h index ca043e48b4..2e2926286c 100644 --- a/src/text/juce_CharPointer_UTF32.h +++ b/src/text/juce_CharPointer_UTF32.h @@ -38,7 +38,7 @@ class CharPointer_UTF32 public: typedef juce_wchar CharType; - inline CharPointer_UTF32 (const CharType* const rawPointer) throw() + inline explicit CharPointer_UTF32 (const CharType* const rawPointer) throw() : data (const_cast (rawPointer)) { } @@ -54,14 +54,35 @@ public: return *this; } + inline CharPointer_UTF32& 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_UTF32& other) const throw() + { + return data == other.data; + } + + /** This is a pointer comparison, it doesn't compare the actual text. */ + inline bool operator!= (const CharPointer_UTF32& other) const throw() + { + return data == other.data; + } + + /** 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 CharType* getAddress() const throw() { return data; } + 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; } + 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; } + inline juce_wchar operator*() const throw() { return *data; } /** Moves this pointer along to the next character in the string. */ inline CharPointer_UTF32& operator++() throw() @@ -90,30 +111,30 @@ public: } /** Moves this pointer forwards by the specified number of characters. */ - inline void operator+= (int numToSkip) throw() + inline void operator+= (const int numToSkip) throw() { data += numToSkip; } - inline void operator-= (int numToSkip) throw() + 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[] (int characterIndex) const throw() + inline juce_wchar& operator[] (const int characterIndex) const throw() { return data [characterIndex]; } /** Returns a pointer which is moved forwards from this one by the specified number of characters. */ - CharPointer_UTF32 operator+ (int numToSkip) const throw() + CharPointer_UTF32 operator+ (const int numToSkip) const throw() { return CharPointer_UTF32 (data + numToSkip); } /** Returns a pointer which is moved backwards from this one by the specified number of characters. */ - CharPointer_UTF32 operator- (int numToSkip) const throw() + CharPointer_UTF32 operator- (const int numToSkip) const throw() { return CharPointer_UTF32 (data - numToSkip); } @@ -124,12 +145,23 @@ public: *data++ = charToWrite; } + inline void replaceChar (const juce_wchar newChar) throw() + { + *data = 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() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 size_t n = 0; - while (data[n] == 0) + while (data[n] != 0) ++n; return n; #else @@ -137,6 +169,12 @@ public: #endif } + /** 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. */ @@ -171,27 +209,31 @@ public: /** Copies a source string to this pointer, advancing this pointer as it goes. */ template - void copyAndAdvance (const CharPointer& src) throw() + void writeAll (const CharPointer& src) throw() { - CharacterFunctions::copyAndAdvance (*this, src); + CharacterFunctions::copyAll (*this, src); } - #if ! JUCE_ANDROID /** Copies a source string to this pointer, advancing this pointer as it goes. */ - void copyAndAdvance (const CharPointer_UTF32& src) throw() + void writeAll (const CharPointer_UTF32& src) throw() { - data = wcscpy (data, src.data); + const CharType* s = src.data; + + while ((*data = *s) != 0) + { + ++data; + ++s; + } } - #endif /** Copies a source string to this pointer, advancing this pointer as it goes. - The maxBytes parameter specifies the maximum number of bytes that can be written + The maxDestBytes parameter specifies the maximum number of bytes that can be written to the destination buffer before stopping. */ template - int copyAndAdvanceUpToBytes (const CharPointer& src, int maxBytes) throw() + int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw() { - return CharacterFunctions::copyAndAdvanceUpToBytes (*this, src, maxBytes); + return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes); } /** Copies a source string to this pointer, advancing this pointer as it goes. @@ -199,9 +241,9 @@ public: written to the destination buffer before stopping (including the terminating null). */ template - void copyAndAdvanceUpToNumChars (const CharPointer& src, int maxChars) throw() + void writeWithCharLimit (const CharPointer& src, const int maxChars) throw() { - CharacterFunctions::copyAndAdvanceUpToNumChars (*this, src, maxChars); + CharacterFunctions::copyWithCharLimit (*this, src, maxChars); } /** Compares this string with another one. */ @@ -211,7 +253,7 @@ public: return CharacterFunctions::compare (*this, other); } - #if ! JUCE_ANDROID + #if ! JUCE_NATIVE_WCHAR_IS_NOT_UTF32 /** Compares this string with another one. */ int compare (const CharPointer_UTF32& other) const throw() { @@ -221,7 +263,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareUpTo (const CharPointer& other, int maxChars) const throw() + int compareUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareUpTo (*this, other, maxChars); } @@ -235,7 +277,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareIgnoreCaseUpTo (const CharPointer& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); } @@ -270,24 +312,6 @@ public: : CharacterFunctions::indexOfChar (*this, charToFind); } - #if JUCE_WINDOWS && ! DOXYGEN - int compareIgnoreCase (const CharPointer_UTF32& other) const throw() - { - return _wcsicmp (data, other.data); - } - - int compareIgnoreCaseUpTo (const CharPointer_UTF32& other, int maxChars) const throw() - { - return _wcsnicmp (data, other.data, maxChars); - } - - int indexOf (const CharPointer_UTF32& stringToFind) const throw() - { - const CharType* const t = wcsstr (data, stringToFind.getAddress()); - return t == 0 ? -1 : (t - data); - } - #endif - /** 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. */ @@ -307,24 +331,9 @@ public: juce_wchar toLowerCase() const throw() { return CharacterFunctions::toLowerCase (*data); } /** Parses this string as a 32-bit integer. */ - int getIntValue32() const throw() - { - #if JUCE_WINDOWS - return _wtoi (data); - #else - return CharacterFunctions::getIntValue (*this); - #endif - } - + int getIntValue32() const throw() { return CharacterFunctions::getIntValue (*this); } /** Parses this string as a 64-bit integer. */ - int64 getIntValue64() const throw() - { - #if JUCE_WINDOWS - return _wtoi64 (data); - #else - return CharacterFunctions::getIntValue (*this); - #endif - } + int64 getIntValue64() const throw() { return CharacterFunctions::getIntValue (*this); } /** Parses this string as a floating point double. */ double getDoubleValue() const throw() { return CharacterFunctions::getDoubleValue (*this); } @@ -332,6 +341,11 @@ public: /** Returns the first non-whitespace character in the string. */ CharPointer_UTF32 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); } + CharPointer_UTF32 atomicSwap (const CharPointer_UTF32& newValue) + { + return CharPointer_UTF32 (reinterpret_cast &> (data).exchange (newValue.data)); + } + private: CharType* data; }; diff --git a/src/text/juce_CharPointer_UTF8.h b/src/text/juce_CharPointer_UTF8.h index e0d6386f6d..33f1bec346 100644 --- a/src/text/juce_CharPointer_UTF8.h +++ b/src/text/juce_CharPointer_UTF8.h @@ -37,7 +37,7 @@ class CharPointer_UTF8 public: typedef char CharType; - inline CharPointer_UTF8 (const CharType* const rawPointer) throw() + inline explicit CharPointer_UTF8 (const CharType* const rawPointer) throw() : data (const_cast (rawPointer)) { } @@ -53,11 +53,32 @@ public: return *this; } + inline CharPointer_UTF8& 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_UTF8& other) const throw() + { + return data == other.data; + } + + /** This is a pointer comparison, it doesn't compare the actual text. */ + inline bool operator!= (const CharPointer_UTF8& other) const throw() + { + return data == other.data; + } + /** Returns the address that this pointer is pointing to. */ - inline CharType* getAddress() const throw() { return data; } + 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; } + inline bool isEmpty() const throw() { return *data == 0; } /** Returns the unicode character that this pointer is pointing to. */ juce_wchar operator*() const throw() @@ -104,7 +125,7 @@ public: { juce_wchar bit = 0x40; - while ((n & bit) != 0 && bit > 0x10) + while ((n & bit) != 0 && bit > 0x8) { ++data; bit >>= 1; @@ -128,7 +149,7 @@ public: uint32 bit = 0x40; int numExtraValues = 0; - while ((n & bit) != 0 && bit > 0x10) + while ((n & bit) != 0 && bit > 0x8) { mask >>= 1; ++numExtraValues; @@ -184,32 +205,6 @@ public: return p; } - /** Writes a unicode character to this string, and advances this pointer to point to the next position. */ - void write (const juce_wchar charToWrite) throw() - { - const uint32 c = (uint32) charToWrite; - - if (c >= 0x80) - { - int numExtraBytes = 1; - if (c >= 0x800) - { - ++numExtraBytes; - if (c >= 0x10000) - ++numExtraBytes; - } - - *data++ = (CharType) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); - - while (--numExtraBytes >= 0) - *data++ = (CharType) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); - } - else - { - *data++ = (CharType) c; - } - } - /** Returns the number of characters in this string. */ size_t length() const throw() { @@ -242,6 +237,12 @@ public: return count; } + /** 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. */ @@ -294,27 +295,65 @@ public: return CharPointer_UTF8 (data + strlen (data)); } + /** Writes a unicode character to this string, and advances this pointer to point to the next position. */ + void write (const juce_wchar charToWrite) throw() + { + const uint32 c = (uint32) charToWrite; + + if (c >= 0x80) + { + int numExtraBytes = 1; + if (c >= 0x800) + { + ++numExtraBytes; + if (c >= 0x10000) + ++numExtraBytes; + } + + *data++ = (CharType) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6))); + + while (--numExtraBytes >= 0) + *data++ = (CharType) (0x80 | (0x3f & (c >> (numExtraBytes * 6)))); + } + else + { + *data++ = (CharType) c; + } + } + + /** Writes a null character to this string (leaving the pointer's position unchanged). */ + inline void writeNull() const throw() + { + *data = 0; + } + /** Copies a source string to this pointer, advancing this pointer as it goes. */ template - void copyAndAdvance (const CharPointer& src) throw() + void writeAll (const CharPointer& src) throw() { - CharacterFunctions::copyAndAdvance (*this, src); + CharacterFunctions::copyAll (*this, src); } /** Copies a source string to this pointer, advancing this pointer as it goes. */ - void copyAndAdvance (const CharPointer_UTF8& src) throw() + void writeAll (const CharPointer_UTF8& src) throw() { - data = (CharType*) strcpy ((char*) data, src.data); + const CharType* s = src.data; + + while ((*data = *s) != 0) + { + ++data; + ++s; + } } /** Copies a source string to this pointer, advancing this pointer as it goes. - The maxBytes parameter specifies the maximum number of bytes that can be written + The maxDestBytes parameter specifies the maximum number of bytes that can be written to the destination buffer before stopping. */ template - int copyAndAdvanceUpToBytes (const CharPointer& src, int maxBytes) throw() + int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) throw() { - return CharacterFunctions::copyAndAdvanceUpToBytes (*this, src, maxBytes); + return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes); } /** Copies a source string to this pointer, advancing this pointer as it goes. @@ -322,9 +361,9 @@ public: written to the destination buffer before stopping (including the terminating null). */ template - void copyAndAdvanceUpToNumChars (const CharPointer& src, int maxChars) throw() + void writeWithCharLimit (const CharPointer& src, const int maxChars) throw() { - CharacterFunctions::copyAndAdvanceUpToNumChars (*this, src, maxChars); + CharacterFunctions::copyWithCharLimit (*this, src, maxChars); } /** Compares this string with another one. */ @@ -336,7 +375,7 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareUpTo (const CharPointer& other, int maxChars) const throw() + int compareUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareUpTo (*this, other, maxChars); } @@ -360,13 +399,13 @@ public: /** Compares this string with another one, up to a specified number of characters. */ template - int compareIgnoreCaseUpTo (const CharPointer& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const throw() { return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars); } /** Compares this string with another one, up to a specified number of characters. */ - int compareIgnoreCaseUpTo (const CharPointer_UTF8& other, int maxChars) const throw() + int compareIgnoreCaseUpTo (const CharPointer_UTF8& other, const int maxChars) const throw() { #if JUCE_WINDOWS return strnicmp (data, other.data, maxChars); @@ -434,6 +473,14 @@ public: /** Returns the first non-whitespace character in the string. */ CharPointer_UTF8 findEndOfWhitespace() const throw() { return CharacterFunctions::findEndOfWhitespace (*this); } + /** These values are the byte-order-mark (BOM) values for a UTF-8 stream. */ + enum + { + byteOrderMark1 = 0xef, + byteOrderMark2 = 0xbb, + byteOrderMark3 = 0xbf + }; + private: CharType* data; }; diff --git a/src/text/juce_CharacterFunctions.cpp b/src/text/juce_CharacterFunctions.cpp index cc582e211b..a89fe8600d 100644 --- a/src/text/juce_CharacterFunctions.cpp +++ b/src/text/juce_CharacterFunctions.cpp @@ -44,18 +44,18 @@ BEGIN_JUCE_NAMESPACE //============================================================================== juce_wchar CharacterFunctions::toUpperCase (const juce_wchar character) throw() { - return towupper (character); + return towupper ((wchar_t) character); } juce_wchar CharacterFunctions::toLowerCase (const juce_wchar character) throw() { - return towlower (character); + return towlower ((wchar_t) character); } bool CharacterFunctions::isUpperCase (const juce_wchar character) throw() { #if JUCE_WINDOWS - return iswupper (character) != 0; + return iswupper ((wchar_t) character) != 0; #else return toLowerCase (character) != character; #endif @@ -64,7 +64,7 @@ bool CharacterFunctions::isUpperCase (const juce_wchar character) throw() bool CharacterFunctions::isLowerCase (const juce_wchar character) throw() { #if JUCE_WINDOWS - return iswlower (character) != 0; + return iswlower ((wchar_t) character) != 0; #else return toUpperCase (character) != character; #endif @@ -78,7 +78,7 @@ bool CharacterFunctions::isWhitespace (const char character) throw() bool CharacterFunctions::isWhitespace (const juce_wchar character) throw() { - return iswspace (character) != 0; + return iswspace ((wchar_t) character) != 0; } bool CharacterFunctions::isDigit (const char character) throw() @@ -88,7 +88,7 @@ bool CharacterFunctions::isDigit (const char character) throw() bool CharacterFunctions::isDigit (const juce_wchar character) throw() { - return iswdigit (character) != 0; + return iswdigit ((wchar_t) character) != 0; } bool CharacterFunctions::isLetter (const char character) throw() @@ -99,7 +99,7 @@ bool CharacterFunctions::isLetter (const char character) throw() bool CharacterFunctions::isLetter (const juce_wchar character) throw() { - return iswalpha (character) != 0; + return iswalpha ((wchar_t) character) != 0; } bool CharacterFunctions::isLetterOrDigit (const char character) throw() @@ -111,7 +111,7 @@ bool CharacterFunctions::isLetterOrDigit (const char character) throw() bool CharacterFunctions::isLetterOrDigit (const juce_wchar character) throw() { - return iswalnum (character) != 0; + return iswalnum ((wchar_t) character) != 0; } int CharacterFunctions::getHexDigitValue (const juce_wchar digit) throw() @@ -138,11 +138,11 @@ int CharacterFunctions::ftime (char* const dest, const int maxChars, const char* int CharacterFunctions::ftime (juce_wchar* const dest, const int maxChars, const juce_wchar* const format, const struct tm* const tm) throw() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 HeapBlock tempDest; tempDest.calloc (maxChars + 2); int result = ftime (tempDest.getData(), maxChars, String (format).toUTF8(), tm); - CharPointer_UTF32 (dest).copyAndAdvance (CharPointer_UTF8 (tempDest.getData())); + CharPointer_UTF32 (dest).writeAll (CharPointer_UTF8 (tempDest.getData())); return result; #else return (int) wcsftime (dest, maxChars, format, tm); diff --git a/src/text/juce_CharacterFunctions.h b/src/text/juce_CharacterFunctions.h index 4b91495199..c206fa43dc 100644 --- a/src/text/juce_CharacterFunctions.h +++ b/src/text/juce_CharacterFunctions.h @@ -31,6 +31,11 @@ #if JUCE_ANDROID && ! DOXYGEN typedef uint32 juce_wchar; #define JUCE_T(stringLiteral) CharPointer_UTF8 (stringLiteral) + #define JUCE_NATIVE_WCHAR_IS_NOT_UTF32 1 +#elif JUCE_WINDOWS && ! DOXYGEN + typedef uint32 juce_wchar; + #define JUCE_T(stringLiteral) L##stringLiteral + #define JUCE_NATIVE_WCHAR_IS_NOT_UTF32 1 #else /** A platform-independent unicode character type. */ typedef wchar_t juce_wchar; @@ -249,52 +254,71 @@ public: static int ftime (juce_wchar* dest, int maxChars, const juce_wchar* format, const struct tm* tm) throw(); //============================================================================== - template - static void copyAndAdvance (DestCharPointerType& dest, SrcCharPointerType src) throw() + template + static size_t lengthUpTo (const CharPointerType& text, const size_t maxCharsToCount) throw() { - juce_wchar c; + size_t len = 0; + CharPointerType t (text); + + while (len < maxCharsToCount && t.getAndAdvance() != 0) + ++len; + + return len; + } - do + + template + static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) throw() + { + for (;;) { - c = src.getAndAdvance(); + const juce_wchar c = src.getAndAdvance(); + + if (c == 0) + break; + dest.write (c); } - while (c != 0); + + dest.writeNull(); } template - static int copyAndAdvanceUpToBytes (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) throw() + static int copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) throw() { int numBytesDone = 0; + maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null) for (;;) { const juce_wchar c = src.getAndAdvance(); - const size_t bytesNeeded = DestCharPointerType::getBytesRequiredFor (c); + const int bytesNeeded = (int) DestCharPointerType::getBytesRequiredFor (c); maxBytes -= bytesNeeded; - if (maxBytes < 0) + if (c == 0 || maxBytes < 0) break; numBytesDone += bytesNeeded; dest.write (c); - if (c == 0) - break; } + dest.writeNull(); return numBytesDone; } template - static void copyAndAdvanceUpToNumChars (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) throw() + static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) throw() { - while (--maxChars >= 0) + while (--maxChars > 0) { const juce_wchar c = src.getAndAdvance(); - dest.write (c); if (c == 0) break; + + dest.write (c); } + + dest.writeNull(); } template @@ -377,7 +401,7 @@ public: static int indexOf (CharPointerType1 haystack, const CharPointerType2& needle) throw() { int index = 0; - const int needleLength = needle.length(); + const int needleLength = (int) needle.length(); for (;;) { diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index 439c761ad3..1cf151e4fa 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -54,37 +54,65 @@ public: text[0] = 0; } + typedef String::CharPointerType CharPointerType; + //============================================================================== - static juce_wchar* createUninitialised (const size_t numChars) + static const CharPointerType createUninitialised (const size_t numChars) { StringHolder* const s = reinterpret_cast (new char [sizeof (StringHolder) + numChars * sizeof (juce_wchar)]); s->refCount.value = 0; s->allocatedNumChars = numChars; - return &(s->text[0]); + return CharPointerType (&(s->text[0])); } - static juce_wchar* createCopy (const juce_wchar* const src, const size_t numChars) + template + static const CharPointerType createFromCharPointer (const CharPointer& text) { - juce_wchar* const dest = createUninitialised (numChars); - copyChars (dest, src, numChars); + if (text.getAddress() == 0 || text.isEmpty()) + return getEmpty(); + + const size_t numChars = text.length(); + const CharPointerType dest (createUninitialised (numChars)); + CharPointerType (dest).writeAll (text); return dest; } - static juce_wchar* createCopy (const char* const src, const size_t numChars) + template + static const CharPointerType createFromCharPointer (const CharPointer& text, size_t maxChars) { - juce_wchar* const dest = createUninitialised (numChars); - CharPointer_UTF32 (dest).copyAndAdvanceUpToNumChars (CharPointer_UTF8 (src), numChars); - dest [numChars] = 0; + if (text.getAddress() == 0 || text.isEmpty()) + return getEmpty(); + + size_t numChars = text.lengthUpTo (maxChars); + if (numChars == 0) + return getEmpty(); + + const CharPointerType dest (createUninitialised (numChars)); + CharPointerType (dest).writeWithCharLimit (text, (int) (numChars + 1)); return dest; } - static inline juce_wchar* getEmpty() throw() + static CharPointerType createFromFixedLength (const juce_wchar* const src, const size_t numChars) { - return &(empty.text[0]); + CharPointerType dest (createUninitialised (numChars)); + copyChars (dest, CharPointerType (src), (int) numChars); + return dest; + } + + static const CharPointerType createFromFixedLength (const char* const src, const size_t numChars) + { + const CharPointerType dest (createUninitialised (numChars)); + CharPointerType (dest).writeWithCharLimit (CharPointer_UTF8 (src), (int) (numChars + 1)); + return dest; + } + + static inline const CharPointerType getEmpty() throw() + { + return CharPointerType (&(empty.text[0])); } //============================================================================== - static void retain (juce_wchar* const text) throw() + static void retain (const CharPointerType& text) throw() { ++(bufferFromText (text)->refCount); } @@ -95,49 +123,49 @@ public: delete[] reinterpret_cast (b); } - static void release (juce_wchar* const text) throw() + static void release (const CharPointerType& text) throw() { release (bufferFromText (text)); } //============================================================================== - static juce_wchar* makeUnique (juce_wchar* const text) + static CharPointerType makeUnique (const CharPointerType& text) { StringHolder* const b = bufferFromText (text); if (b->refCount.get() <= 0) return text; - juce_wchar* const newText = createCopy (text, b->allocatedNumChars); + CharPointerType newText (createFromFixedLength (text, b->allocatedNumChars)); release (b); return newText; } - static juce_wchar* makeUniqueWithSize (juce_wchar* const text, size_t numChars) + static CharPointerType makeUniqueWithSize (const CharPointerType& text, size_t numChars) { StringHolder* const b = bufferFromText (text); if (b->refCount.get() <= 0 && b->allocatedNumChars >= numChars) return text; - juce_wchar* const newText = createUninitialised (jmax (b->allocatedNumChars, numChars)); + CharPointerType newText (createUninitialised (jmax (b->allocatedNumChars, numChars))); copyChars (newText, text, b->allocatedNumChars); release (b); return newText; } - static size_t getAllocatedNumChars (juce_wchar* const text) throw() + static size_t getAllocatedNumChars (const CharPointerType& text) throw() { return bufferFromText (text)->allocatedNumChars; } - static void copyChars (juce_wchar* const dest, const juce_wchar* const src, const size_t numChars) throw() + static void copyChars (CharPointerType dest, const CharPointerType& src, const size_t numChars) throw() { - jassert (src != 0 && dest != 0); - memcpy (dest, src, numChars * sizeof (juce_wchar)); - dest [numChars] = 0; + jassert (src.getAddress() != 0 && dest.getAddress() != 0); + memcpy (dest.getAddress(), src.getAddress(), numChars * sizeof (juce_wchar)); + CharPointerType (dest + (int) numChars).writeNull(); } //============================================================================== @@ -148,10 +176,10 @@ public: static StringHolder empty; private: - static inline StringHolder* bufferFromText (void* const text) throw() + static inline StringHolder* bufferFromText (const CharPointerType& text) throw() { // (Can't use offsetof() here because of warnings about this not being a POD) - return reinterpret_cast (static_cast (text) + return reinterpret_cast (reinterpret_cast (text.getAddress()) - (reinterpret_cast (reinterpret_cast (1)->text) - 1)); } }; @@ -160,14 +188,7 @@ StringHolder StringHolder::empty; const String String::empty; //============================================================================== -void String::createInternal (const juce_wchar* const t, const size_t numChars) -{ - jassert (t[numChars] == 0); // must have a null terminator - - text = StringHolder::createCopy (t, numChars); -} - -void String::appendInternal (const juce_wchar* const newText, const int numExtraChars) +void String::appendFixedLength (const juce_wchar* const newText, const int numExtraChars) { if (numExtraChars > 0) { @@ -175,7 +196,7 @@ void String::appendInternal (const juce_wchar* const newText, const int numExtra const int newTotalLen = oldLen + numExtraChars; text = StringHolder::makeUniqueWithSize (text, newTotalLen); - StringHolder::copyChars (text + oldLen, newText, numExtraChars); + StringHolder::copyChars (text + oldLen, CharPointer_UTF32 (newText), numExtraChars); } } @@ -208,9 +229,8 @@ void String::swapWith (String& other) throw() String& String::operator= (const String& other) throw() { - juce_wchar* const newText = other.text; - StringHolder::retain (newText); - StringHolder::release (reinterpret_cast &> (text).exchange (newText)); + StringHolder::retain (other.text); + StringHolder::release (text.atomicSwap (other.text)); return *this; } @@ -222,6 +242,7 @@ String::String (const Preallocation& preallocationSize) } String::String (const String& stringToCopy, const size_t charsToAllocate) + : text (0) { const size_t otherSize = StringHolder::getAllocatedNumChars (stringToCopy.text); text = StringHolder::createUninitialised (jmax (charsToAllocate, otherSize)); @@ -229,45 +250,55 @@ String::String (const String& stringToCopy, const size_t charsToAllocate) } String::String (const char* const t) + : text (StringHolder::createFromCharPointer (CharPointer_UTF8 (t))) { - if (t != 0 && *t != 0) - text = StringHolder::createCopy (t, CharPointer_UTF8 (t).length()); - else - text = StringHolder::getEmpty(); } String::String (const juce_wchar* const t) + : text (StringHolder::createFromCharPointer (CharPointer_UTF32 (t))) { - if (t != 0 && *t != 0) - text = StringHolder::createCopy (t, CharPointer_UTF32 (t).length()); - else - text = StringHolder::getEmpty(); } -String::String (const char* const t, const size_t maxChars) +String::String (const CharPointer_UTF8& t) + : text (StringHolder::createFromCharPointer (t)) { - int i; - for (i = 0; (size_t) i < maxChars; ++i) - if (t[i] == 0) - break; +} - if (i > 0) - text = StringHolder::createCopy (t, i); - else - text = StringHolder::getEmpty(); +String::String (const CharPointer_UTF16& t) + : text (StringHolder::createFromCharPointer (t)) +{ } -String::String (const juce_wchar* const t, const size_t maxChars) +String::String (const CharPointer_UTF32& t) + : text (StringHolder::createFromCharPointer (t)) { - int i; - for (i = 0; (size_t) i < maxChars; ++i) - if (t[i] == 0) - break; +} - if (i > 0) - text = StringHolder::createCopy (t, i); - else - text = StringHolder::getEmpty(); +String::String (const CharPointer_UTF32& t, const size_t maxChars) + : text (StringHolder::createFromCharPointer (t, maxChars)) +{ +} + +#if JUCE_WINDOWS +String::String (const wchar_t* const t) + : text (StringHolder::createFromCharPointer (CharPointer_UTF16 (t))) +{ +} + +String::String (const wchar_t* const t, size_t maxChars) + : text (StringHolder::createFromCharPointer (CharPointer_UTF16 (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) @@ -282,7 +313,7 @@ const String String::charToString (const juce_wchar character) namespace NumberToStringConverters { // pass in a pointer to the END of a buffer.. - juce_wchar* int64ToString (juce_wchar* t, const int64 n) throw() + juce_wchar* numberToString (juce_wchar* t, const int64 n) throw() { *--t = 0; int64 v = (n >= 0) ? n : -n; @@ -300,7 +331,7 @@ namespace NumberToStringConverters return t; } - juce_wchar* uint64ToString (juce_wchar* t, int64 v) throw() + juce_wchar* numberToString (juce_wchar* t, uint64 v) throw() { *--t = 0; @@ -314,10 +345,10 @@ namespace NumberToStringConverters return t; } - juce_wchar* intToString (juce_wchar* t, const int n) throw() + juce_wchar* numberToString (juce_wchar* t, const int n) throw() { if (n == (int) 0x80000000) // (would cause an overflow) - return int64ToString (t, n); + return numberToString (t, (int64) n); *--t = 0; int v = abs (n); @@ -335,7 +366,7 @@ namespace NumberToStringConverters return t; } - juce_wchar* uintToString (juce_wchar* t, unsigned int v) throw() + juce_wchar* numberToString (juce_wchar* t, unsigned int v) throw() { *--t = 0; @@ -391,77 +422,71 @@ namespace NumberToStringConverters return buffer; } } + + template + const String::CharPointerType createFromInteger (const IntegerType number) + { + juce_wchar buffer [32]; + juce_wchar* const end = buffer + numElementsInArray (buffer); + juce_wchar* const start = numberToString (end, number); + + return StringHolder::createFromFixedLength (start, end - start - 1); + } + + const String::CharPointerType createFromDouble (const double number, const int numberOfDecimalPlaces) + { + char buffer [48]; + size_t len; + char* const start = doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len); + return StringHolder::createFromFixedLength (start, len); + } } //============================================================================== String::String (const int number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::intToString (end, number); - createInternal (start, end - start - 1); } String::String (const unsigned int number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::uintToString (end, number); - createInternal (start, end - start - 1); } String::String (const short number) + : text (NumberToStringConverters::createFromInteger ((int) number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::intToString (end, (int) number); - createInternal (start, end - start - 1); } String::String (const unsigned short number) + : text (NumberToStringConverters::createFromInteger ((unsigned int) number)) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::uintToString (end, (unsigned int) number); - createInternal (start, end - start - 1); } String::String (const int64 number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [32]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::int64ToString (end, number); - createInternal (start, end - start - 1); } String::String (const uint64 number) + : text (NumberToStringConverters::createFromInteger (number)) { - juce_wchar buffer [32]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::uint64ToString (end, number); - createInternal (start, end - start - 1); } String::String (const float number, const int numberOfDecimalPlaces) + : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces)) { - char buffer [48]; - size_t len; - char* const start = NumberToStringConverters::doubleToString (buffer, numElementsInArray (buffer), (double) number, numberOfDecimalPlaces, len); - text = StringHolder::createCopy (start, len); } String::String (const double number, const int numberOfDecimalPlaces) + : text (NumberToStringConverters::createFromDouble (number, numberOfDecimalPlaces)) { - char buffer [48]; - size_t len; - char* const start = NumberToStringConverters::doubleToString (buffer, numElementsInArray (buffer), number, numberOfDecimalPlaces, len); - text = StringHolder::createCopy (start, len); } //============================================================================== int String::length() const throw() { - return CharPointer_UTF32 (text).length(); + return (int) text.length(); } int String::hashCode() const throw() @@ -502,6 +527,21 @@ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const juce_wchar* return string1.compare (string2) == 0; } +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF8& string2) throw() +{ + return string1.getCharPointer().compare (string2) == 0; +} + +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF16& string2) throw() +{ + return string1.getCharPointer().compare (string2) == 0; +} + +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF32& string2) throw() +{ + return string1.getCharPointer().compare (string2) == 0; +} + JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) throw() { return string1.compare (string2) != 0; @@ -517,6 +557,21 @@ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const juce_wchar* return string1.compare (string2) != 0; } +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF8& string2) throw() +{ + return string1.getCharPointer().compare (string2) != 0; +} + +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF16& string2) throw() +{ + return string1.getCharPointer().compare (string2) != 0; +} + +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF32& string2) throw() +{ + return string1.getCharPointer().compare (string2) != 0; +} + JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) throw() { return string1.compare (string2) > 0; @@ -539,50 +594,50 @@ JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& str bool String::equalsIgnoreCase (const juce_wchar* t) const throw() { - return t != 0 ? CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF32 (t)) == 0 + return t != 0 ? text.compareIgnoreCase (CharPointer_UTF32 (t)) == 0 : isEmpty(); } bool String::equalsIgnoreCase (const char* t) const throw() { - return t != 0 ? CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF8 (t)) == 0 + return t != 0 ? text.compareIgnoreCase (CharPointer_UTF8 (t)) == 0 : isEmpty(); } bool String::equalsIgnoreCase (const String& other) const throw() { return text == other.text - || CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF32 (other.text)) == 0; + || text.compareIgnoreCase (other.text) == 0; } int String::compare (const String& other) const throw() { - return (text == other.text) ? 0 : CharPointer_UTF32 (text).compare (CharPointer_UTF32 (other.text)); + return (text == other.text) ? 0 : text.compare (other.text); } int String::compare (const char* other) const throw() { - return other == 0 ? isEmpty() : CharPointer_UTF32 (text).compare (CharPointer_UTF8 (other)); + return text.compare (CharPointer_UTF8 (other)); } int String::compare (const juce_wchar* other) const throw() { - return other == 0 ? isEmpty() : CharPointer_UTF32 (text).compare (CharPointer_UTF32 (other)); + return text.compare (CharPointer_UTF32 (other)); } int String::compareIgnoreCase (const String& other) const throw() { - return (text == other.text) ? 0 : CharPointer_UTF32 (text).compareIgnoreCase (CharPointer_UTF32 (other.text)); + return (text == other.text) ? 0 : text.compareIgnoreCase (other.text); } int String::compareLexicographically (const String& other) const throw() { - CharPointer_UTF32 s1 (text); + CharPointerType s1 (text); while (! (s1.isEmpty() || s1.isLetterOrDigit())) ++s1; - CharPointer_UTF32 s2 (other.text); + CharPointerType s2 (other.text); while (! (s2.isEmpty() || s2.isLetterOrDigit())) ++s2; @@ -591,10 +646,14 @@ int String::compareLexicographically (const String& other) const throw() } //============================================================================== +void String::append (const String& textToAppend, size_t maxCharsToTake) +{ + appendCharPointer (textToAppend.text, maxCharsToTake); +} + String& String::operator+= (const juce_wchar* const t) { - if (t != 0) - appendInternal (t, CharPointer_UTF32 (t).length()); + appendCharPointer (CharPointer_UTF32 (t)); return *this; } @@ -602,45 +661,42 @@ String& String::operator+= (const juce_wchar* const t) String& String::operator+= (const String& other) { if (isEmpty()) - operator= (other); - else - appendInternal (other.text, other.length()); + return operator= (other); + appendCharPointer (other.text); return *this; } String& String::operator+= (const char ch) { - const juce_wchar asString[] = { (juce_wchar) ch, 0 }; - return operator+= (static_cast (asString)); + return operator+= ((juce_wchar) ch); } String& String::operator+= (const juce_wchar ch) { - const juce_wchar asString[] = { (juce_wchar) ch, 0 }; + const juce_wchar asString[] = { ch, 0 }; return operator+= (static_cast (asString)); } -String& String::operator+= (const int number) +#if JUCE_WINDOWS +String& String::operator+= (wchar_t ch) { - juce_wchar buffer [16]; - juce_wchar* const end = buffer + numElementsInArray (buffer); - juce_wchar* const start = NumberToStringConverters::intToString (end, number); - appendInternal (start, (int) (end - start)); - return *this; + return operator+= ((juce_wchar) ch); } -void String::append (const juce_wchar* const other, const int howMany) +String& String::operator+= (const wchar_t* t) { - if (howMany > 0) - { - int i; - for (i = 0; i < howMany; ++i) - if (other[i] == 0) - break; + return operator+= (String (t)); +} +#endif - appendInternal (other, i); - } +String& String::operator+= (const int number) +{ + juce_wchar buffer [16]; + juce_wchar* const end = buffer + numElementsInArray (buffer); + juce_wchar* const start = NumberToStringConverters::numberToString (end, number); + appendFixedLength (start, (int) (end - start)); + return *this; } //============================================================================== @@ -691,6 +747,25 @@ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const juce_wchar return string1 += string2; } +#if JUCE_WINDOWS +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, wchar_t string2) +{ + return string1 += string2; +} + +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const wchar_t* string2) +{ + string1.appendCharPointer (CharPointer_UTF16 (string2)); + return string1; +} + +JUCE_API const String JUCE_CALLTYPE operator+ (const wchar_t* string1, const String& string2) +{ + String s (string1); + return s += string2; +} +#endif + JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const char characterToAppend) { return string1 += characterToAppend; @@ -783,7 +858,7 @@ int String::lastIndexOfChar (const juce_wchar character) const throw() int String::indexOf (const String& t) const throw() { - return t.isEmpty() ? 0 : CharPointer_UTF32 (text).indexOf (CharPointer_UTF32 (t.text)); + return t.isEmpty() ? 0 : text.indexOf (t.text); } int String::indexOfChar (const int startIndex, @@ -813,13 +888,13 @@ int String::indexOfAnyOf (const String& charactersToLookFor, if (startIndex > 0 && startIndex >= length()) return -1; - CharPointer_UTF32 t (text); + CharPointerType t (text); int i = jmax (0, startIndex); t += i; while (! t.isEmpty()) { - if (CharPointer_UTF32 (charactersToLookFor.text).indexOf (*t, ignoreCase) >= 0) + if (charactersToLookFor.text.indexOf (*t, ignoreCase) >= 0) return i; ++i; @@ -834,7 +909,7 @@ int String::indexOf (const int startIndex, const String& other) const throw() if (startIndex > 0 && startIndex >= length()) return -1; - int i = CharPointer_UTF32 (text + jmax (0, startIndex)).indexOf (CharPointer_UTF32 (other.text)); + int i = CharPointerType (text + jmax (0, startIndex)).indexOf (other.text); return i >= 0 ? i + startIndex : -1; } @@ -847,7 +922,7 @@ int String::indexOfIgnoreCase (const String& other) const throw() const int end = length() - len; for (int i = 0; i <= end; ++i) - if (CharPointer_UTF32 (text + i).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (CharPointerType (text + i).compareIgnoreCaseUpTo (other.text, len) == 0) return i; return -1; @@ -861,7 +936,7 @@ int String::indexOfIgnoreCase (const int startIndex, const String& other) const const int end = length() - len; for (int i = jmax (0, startIndex); i <= end; ++i) - if (CharPointer_UTF32 (text + i).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (CharPointerType (text + i).compareIgnoreCaseUpTo (other.text, len) == 0) return i; } @@ -877,11 +952,11 @@ int String::lastIndexOf (const String& other) const throw() if (i >= 0) { - const juce_wchar* n = text + i; + CharPointerType n (text + i); while (i >= 0) { - if (CharPointer_UTF32 (n).compareUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (n.compareUpTo (other.text, len) == 0) return i; --n; @@ -902,11 +977,11 @@ int String::lastIndexOfIgnoreCase (const String& other) const throw() if (i >= 0) { - const juce_wchar* n = text + i; + CharPointerType n (text + i); while (i >= 0) { - if (CharPointer_UTF32 (n).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), len) == 0) + if (n.compareIgnoreCaseUpTo (other.text, len) == 0) return i; --n; @@ -921,7 +996,7 @@ int String::lastIndexOfIgnoreCase (const String& other) const throw() int String::lastIndexOfAnyOf (const String& charactersToLookFor, const bool ignoreCase) const throw() { for (int i = length(); --i >= 0;) - if (CharPointer_UTF32 (charactersToLookFor.text).indexOf (text[i], ignoreCase) >= 0) + if (charactersToLookFor.text.indexOf (text[i], ignoreCase) >= 0) return i; return -1; @@ -957,13 +1032,13 @@ int String::indexOfWholeWord (const String& word) const throw() { if (word.isNotEmpty()) { - CharPointer_UTF32 t (text); + CharPointerType t (text); const int wordLen = word.length(); - const int end = t.length() - wordLen; + const int end = (int) t.length() - wordLen; for (int i = 0; i <= end; ++i) { - if (t.compareUpTo (CharPointer_UTF32 (word.text), wordLen) == 0 + if (t.compareUpTo (word.text, wordLen) == 0 && (i == 0 || ! (t - 1).isLetterOrDigit()) && ! (t + wordLen).isLetterOrDigit()) return i; @@ -979,13 +1054,13 @@ int String::indexOfWholeWordIgnoreCase (const String& word) const throw() { if (word.isNotEmpty()) { - CharPointer_UTF32 t (text); + CharPointerType t (text); const int wordLen = word.length(); - const int end = t.length() - wordLen; + const int end = (int) t.length() - wordLen; for (int i = 0; i <= end; ++i) { - if (t.compareIgnoreCaseUpTo (CharPointer_UTF32 (word.text), wordLen) == 0 + if (t.compareIgnoreCaseUpTo (word.text, wordLen) == 0 && (i == 0 || ! (t + -1).isLetterOrDigit()) && ! (t + wordLen).isLetterOrDigit()) return i; @@ -1010,16 +1085,16 @@ bool String::containsWholeWordIgnoreCase (const String& wordToLookFor) const thr //============================================================================== namespace WildCardHelpers { - int indexOfMatch (CharPointer_UTF32 wildcard, - CharPointer_UTF32 test, + int indexOfMatch (const String::CharPointerType& wildcard, + String::CharPointerType test, const bool ignoreCase) throw() { int start = 0; while (! test.isEmpty()) { - CharPointer_UTF32 t (test); - CharPointer_UTF32 w (wildcard); + String::CharPointerType t (test); + String::CharPointerType w (wildcard); for (;;) { @@ -1055,8 +1130,8 @@ namespace WildCardHelpers bool String::matchesWildcard (const String& wildcard, const bool ignoreCase) const throw() { - CharPointer_UTF32 w (wildcard.text); - CharPointer_UTF32 t (text); + CharPointerType w (wildcard.text); + CharPointerType t (text); for (;;) { @@ -1083,10 +1158,12 @@ bool String::matchesWildcard (const String& wildcard, const bool ignoreCase) con //============================================================================== const String String::repeatedString (const String& stringToRepeat, int numberOfTimesToRepeat) { + if (numberOfTimesToRepeat <= 0) + return String::empty; + const int len = stringToRepeat.length(); String result (Preallocation (len * numberOfTimesToRepeat + 1)); - juce_wchar* n = result.text; - *n = 0; + CharPointerType n (result.text); while (--numberOfTimesToRepeat >= 0) { @@ -1106,11 +1183,11 @@ const String String::paddedLeft (const juce_wchar padCharacter, int minimumLengt return *this; String result (Preallocation (minimumLength + 1)); - juce_wchar* n = result.text; + CharPointerType n (result.text); minimumLength -= len; while (--minimumLength >= 0) - *n++ = padCharacter; + n.write (padCharacter); StringHolder::copyChars (n, text, len); return result; @@ -1125,13 +1202,13 @@ const String String::paddedRight (const juce_wchar padCharacter, int minimumLeng return *this; String result (*this, (size_t) minimumLength); - juce_wchar* n = result.text + len; + CharPointerType n (result.text + len); minimumLength -= len; while (--minimumLength >= 0) - *n++ = padCharacter; + n.write (padCharacter); - *n = 0; + n.writeNull(); return result; } @@ -1215,12 +1292,12 @@ const String String::replaceCharacter (const juce_wchar charToReplace, const juc return *this; String result (*this, size_t()); - juce_wchar* t = result.text + index; + CharPointerType t (result.text + index); - while (*t != 0) + while (! t.isEmpty()) { if (*t == charToReplace) - *t = charToInsert; + t.replaceChar (charToInsert); ++t; } @@ -1232,18 +1309,18 @@ const String String::replaceCharacters (const String& charactersToReplace, const String& charactersToInsertInstead) const { String result (*this, size_t()); - juce_wchar* t = result.text; + CharPointerType t (result.text); const int len2 = charactersToInsertInstead.length(); // the two strings passed in are supposed to be the same length! jassert (len2 == charactersToReplace.length()); - while (*t != 0) + while (! t.isEmpty()) { const int index = charactersToReplace.indexOfChar (*t); if (isPositiveAndBelow (index, len2)) - *t = charactersToInsertInstead [index]; + t.replaceChar (charactersToInsertInstead [index]); ++t; } @@ -1254,12 +1331,12 @@ const String String::replaceCharacters (const String& charactersToReplace, //============================================================================== bool String::startsWith (const String& other) const throw() { - return CharPointer_UTF32 (text).compareUpTo (CharPointer_UTF32 (other.text), other.length()) == 0; + return text.compareUpTo (other.text, other.length()) == 0; } bool String::startsWithIgnoreCase (const String& other) const throw() { - return CharPointer_UTF32 (text).compareIgnoreCaseUpTo (CharPointer_UTF32 (other.text), other.length()) == 0; + return text.compareIgnoreCaseUpTo (other.text, other.length()) == 0; } bool String::startsWithChar (const juce_wchar character) const throw() @@ -1283,7 +1360,7 @@ bool String::endsWith (const String& other) const throw() const int otherLen = other.length(); return thisLen >= otherLen - && CharPointer_UTF32 (text + thisLen - otherLen).compare (CharPointer_UTF32 (other.text)) == 0; + && CharPointerType (text + thisLen - otherLen).compare (other.text) == 0; } bool String::endsWithIgnoreCase (const String& other) const throw() @@ -1292,7 +1369,7 @@ bool String::endsWithIgnoreCase (const String& other) const throw() const int otherLen = other.length(); return thisLen >= otherLen - && CharPointer_UTF32 (text + thisLen - otherLen).compareIgnoreCase (CharPointer_UTF32 (other.text)) == 0; + && CharPointerType (text + thisLen - otherLen).compareIgnoreCase (other.text) == 0; } //============================================================================== @@ -1300,8 +1377,8 @@ const String String::toUpperCase() const { String result (Preallocation (this->length())); - CharPointer_UTF32 dest (result.text); - CharPointer_UTF32 src (text); + CharPointerType dest (result.text); + CharPointerType src (text); for (;;) { @@ -1321,8 +1398,8 @@ const String String::toLowerCase() const { String result (Preallocation (this->length())); - CharPointer_UTF32 dest (result.text); - CharPointer_UTF32 src (text); + CharPointerType dest (result.text); + CharPointerType src (text); for (;;) { @@ -1492,13 +1569,13 @@ const String String::trim() const int start = 0; - while (CharPointer_UTF32 (text + start).isWhitespace()) + while ((text + start).isWhitespace()) ++start; const int len = length(); int end = len - 1; - while ((end >= start) && CharPointer_UTF32 (text + end).isWhitespace()) + while ((end >= start) && (text + end).isWhitespace()) --end; ++end; @@ -1516,12 +1593,12 @@ const String String::trimStart() const if (isEmpty()) return empty; - CharPointer_UTF32 t (text); + CharPointerType t (text); while (t.isWhitespace()) ++t; - if (t.getAddress() == text) + if (t == text) return *this; return String (t.getAddress()); @@ -1532,7 +1609,7 @@ const String String::trimEnd() const if (isEmpty()) return empty; - CharPointer_UTF32 endT (text); + CharPointerType endT (text); endT = endT.findTerminatingNull() - 1; while ((endT.getAddress() >= text) && endT.isWhitespace()) @@ -1543,7 +1620,7 @@ const String String::trimEnd() const const String String::trimCharactersAtStart (const String& charactersToTrim) const { - const juce_wchar* t = text; + CharPointerType t (text); while (charactersToTrim.containsChar (*t)) ++t; @@ -1576,18 +1653,21 @@ const String String::retainCharacters (const String& charactersToRetain) const return empty; String result (Preallocation (StringHolder::getAllocatedNumChars (text))); - juce_wchar* dst = result.text; - const juce_wchar* src = text; + CharPointerType dst (result.text); + CharPointerType src (text); - while (*src != 0) + for (;;) { - if (charactersToRetain.containsChar (*src)) - *dst++ = *src; + const juce_wchar c = src.getAndAdvance(); - ++src; + if (c == 0) + break; + + if (charactersToRetain.containsChar (c)) + dst.write (c); } - *dst = 0; + dst.writeNull(); return result; } @@ -1597,18 +1677,21 @@ const String String::removeCharacters (const String& charactersToRemove) const return empty; String result (Preallocation (StringHolder::getAllocatedNumChars (text))); - juce_wchar* dst = result.text; - const juce_wchar* src = text; + CharPointerType dst (result.text); + CharPointerType src (text); - while (*src != 0) + for (;;) { - if (! charactersToRemove.containsChar (*src)) - *dst++ = *src; + const juce_wchar c = src.getAndAdvance(); - ++src; + if (c == 0) + break; + + if (! charactersToRemove.containsChar (c)) + dst.write (c); } - *dst = 0; + dst.writeNull(); return result; } @@ -1645,7 +1728,7 @@ const String String::initialSectionNotContaining (const String& charactersToStop bool String::containsOnly (const String& chars) const throw() { - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) if (! chars.containsChar (t.getAndAdvance())) @@ -1667,7 +1750,7 @@ bool String::containsAnyOf (const String& chars) const throw() bool String::containsNonWhitespaceChars() const throw() { - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) { @@ -1693,28 +1776,24 @@ const String String::formatted (const juce_wchar* const pf, ... ) for (;;) { -#if JUCE_LINUX && JUCE_64BIT + #if JUCE_LINUX && JUCE_64BIT va_list tempArgs; va_copy (tempArgs, args); - const int num = (int) vswprintf (result.text, bufferSize - 1, pf, tempArgs); + const int num = (int) vswprintf (result.text.getAddress(), bufferSize - 1, pf, tempArgs); va_end (tempArgs); -#elif JUCE_WINDOWS - #if JUCE_MSVC - #pragma warning (push) - #pragma warning (disable: 4996) - #endif - const int num = (int) _vsnwprintf (result.text, bufferSize - 1, pf, args); - #if JUCE_MSVC - #pragma warning (pop) - #endif -#elif JUCE_ANDROID + #elif JUCE_WINDOWS + HeapBlock temp (bufferSize); + const int num = (int) _vsnwprintf (temp.getData(), bufferSize - 1, String (pf).toUTF16(), args); + if (num > 0) + CharPointerType (result.text).writeAll (CharPointer_UTF16 (temp.getData())); + #elif JUCE_ANDROID HeapBlock temp (bufferSize); const int num = (int) vsnprintf (temp.getData(), bufferSize - 1, String (pf).toUTF8(), args); if (num > 0) - CharPointer_UTF32 (result.text).copyAndAdvance (CharPointer_UTF8 (temp.getData())); -#else - const int num = (int) vswprintf (result.text, bufferSize - 1, pf, args); -#endif + CharPointerType (result.text).writeAll (CharPointer_UTF8 (temp.getData())); + #else + const int num = (int) vswprintf (result.text.getAddress(), bufferSize - 1, pf, args); + #endif if (num > 0) return result; @@ -1733,15 +1812,14 @@ const String String::formatted (const juce_wchar* const pf, ... ) //============================================================================== int String::getIntValue() const throw() { - return CharPointer_UTF32 (text).getIntValue32(); + return text.getIntValue32(); } int String::getTrailingIntValue() const throw() { int n = 0; int mult = 1; - CharPointer_UTF32 t (text); - t = t.findTerminatingNull(); + CharPointerType t (text.findTerminatingNull()); while ((--t).getAddress() >= text) { @@ -1762,7 +1840,7 @@ int String::getTrailingIntValue() const throw() int64 String::getLargeIntValue() const throw() { - return CharPointer_UTF32 (text).getIntValue64(); + return text.getIntValue64(); } float String::getFloatValue() const throw() @@ -1772,7 +1850,7 @@ float String::getFloatValue() const throw() double String::getDoubleValue() const throw() { - return CharPointer_UTF32 (text).getDoubleValue(); + return text.getDoubleValue(); } static const char* const hexDigits = "0123456789abcdef"; @@ -1829,26 +1907,26 @@ const String String::toHexString (const unsigned char* data, const int size, con String s (Preallocation ((size_t) numChars)); - juce_wchar* d = s.text; + CharPointerType dest (s.text); for (int i = 0; i < size; ++i) { - *d++ = (juce_wchar) hexDigits [(*data) >> 4]; - *d++ = (juce_wchar) hexDigits [(*data) & 0xf]; + dest.write ((juce_wchar) hexDigits [(*data) >> 4]); + dest.write ((juce_wchar) hexDigits [(*data) & 0xf]); ++data; if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1)) - *d++ = ' '; + dest.write ((juce_wchar) ' '); } - *d = 0; + dest.writeNull(); return s; } int String::getHexValue32() const throw() { int result = 0; - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) { @@ -1864,7 +1942,7 @@ int String::getHexValue32() const throw() int64 String::getHexValue64() const throw() { int64 result = 0; - CharPointer_UTF32 t (text); + CharPointerType t (text); while (! t.isEmpty()) { @@ -1890,10 +1968,10 @@ const String String::createStringFromData (const void* const data_, const int si { return charToString ((char) data[0]); } - else if ((data[0] == (uint8) 0xfe && data[1] == (uint8) 0xff) // UTF-16 BOM - || (data[0] == (uint8) 0xff && data[1] == (uint8) 0xfe)) + else if ((data[0] == (uint8) CharPointer_UTF16::byteOrderMarkBE1 && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkBE2) + || (data[0] == (uint8) CharPointer_UTF16::byteOrderMarkLE1 && data[1] == (uint8) CharPointer_UTF16::byteOrderMarkLE1)) { - const bool bigEndian = (data[0] == (uint8) 0xfe); + const bool bigEndian = (data[0] == (uint8) CharPointer_UTF16::byteOrderMarkBE1); const int numChars = size / 2 - 1; String result; @@ -1918,7 +1996,10 @@ const String String::createStringFromData (const void* const data_, const int si } else { - if (size >= 3 && data[0] == (uint8) 0xef && data[1] == (uint8) 0xbb && data[2] == (uint8) 0xbf) // UTF-8 BOM + if (size >= 3 + && data[0] == (uint8) CharPointer_UTF8::byteOrderMark1 + && data[1] == (uint8) CharPointer_UTF8::byteOrderMark2 + && data[2] == (uint8) CharPointer_UTF8::byteOrderMark3) return String::fromUTF8 ((const char*) data + 3, size - 3); return String::fromUTF8 ((const char*) data, size); @@ -1931,110 +2012,89 @@ void* String::createSpaceAtEndOfBuffer (const size_t numExtraBytes) const const int currentLen = length() + 1; String& mutableThis = const_cast (*this); - mutableThis.text = StringHolder::makeUniqueWithSize (mutableThis.text, currentLen + 1 + numExtraBytes / sizeof (juce_wchar)); + mutableThis.preallocateStorage (currentLen + 1 + numExtraBytes / sizeof (juce_wchar)); - return mutableThis.text + currentLen; + return (mutableThis.text + currentLen).getAddress(); } -const char* String::toUTF8() const +const CharPointer_UTF8 String::toUTF8() const { if (isEmpty()) - return reinterpret_cast (text); + return CharPointer_UTF8 (reinterpret_cast (text.getAddress())); - const int utf8BytesNeeded = getNumBytesAsUTF8(); - char* const utf8Area = static_cast (createSpaceAtEndOfBuffer (utf8BytesNeeded)); + const size_t extraBytesNeeded = CharPointer_UTF8::getBytesRequiredFor (text); + CharPointer_UTF8 extraSpace (static_cast (createSpaceAtEndOfBuffer (extraBytesNeeded))); #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..) - *(juce_wchar*) (utf8Area + (utf8BytesNeeded & ~(sizeof (juce_wchar) - 1))) = 0; + *(juce_wchar*) (addBytesToPointer (extraSpace.getAddress(), (extraBytesNeeded & ~(sizeof (juce_wchar) - 1)))) = 0; #endif - copyToUTF8 (utf8Area, std::numeric_limits::max()); - return utf8Area; + CharPointer_UTF8 (extraSpace).writeAll (text); + return extraSpace; } -int String::copyToUTF8 (char* const buffer, const int maxBufferSizeBytes) const throw() +CharPointer_UTF16 String::toUTF16() const { - jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! + if (isEmpty()) + return CharPointer_UTF16 (reinterpret_cast (text.getAddress())); - return CharPointer_UTF8 (buffer).copyAndAdvanceUpToBytes (CharPointer_UTF32 (text), maxBufferSizeBytes); -} + const size_t extraBytesNeeded = CharPointer_UTF16::getBytesRequiredFor (text); + CharPointer_UTF16 extraSpace (static_cast (createSpaceAtEndOfBuffer (extraBytesNeeded))); -int String::getNumBytesAsUTF8() const throw() -{ - return CharPointer_UTF8::getBytesRequiredFor (CharPointer_UTF32 (text)); + #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..) + *(juce_wchar*) (addBytesToPointer (extraSpace.getAddress(), (extraBytesNeeded & ~(sizeof (juce_wchar) - 1)))) = 0; + #endif + + CharPointer_UTF16 (extraSpace).writeAll (text); + return extraSpace; } -const String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) +int String::copyToUTF8 (CharPointer_UTF8::CharType* const buffer, const int maxBufferSizeBytes) const throw() { - if (buffer == 0) - return empty; - - if (bufferSizeBytes < 0) - bufferSizeBytes = std::numeric_limits::max(); - - size_t numBytes; - for (numBytes = 0; numBytes < (size_t) bufferSizeBytes; ++numBytes) - if (buffer [numBytes] == 0) - break; - - String result (Preallocation (numBytes + 1)); - juce_wchar* dest = result.text; + jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! - size_t i = 0; - while (i < numBytes) - { - const char c = buffer [i++]; + if (buffer == 0) + return (int) CharPointer_UTF8::getBytesRequiredFor (text); - if (c < 0) - { - unsigned int mask = 0x7f; - int bit = 0x40; - int numExtraValues = 0; + return CharPointer_UTF8 (buffer).writeWithDestByteLimit (text, maxBufferSizeBytes); +} - while (bit != 0 && (c & bit) != 0) - { - bit >>= 1; - mask >>= 1; - ++numExtraValues; - } +int String::copyToUTF16 (CharPointer_UTF16::CharType* const buffer, int maxBufferSizeBytes) const throw() +{ + jassert (maxBufferSizeBytes >= 0); // keep this value positive, or no characters will be copied! - int n = (mask & (unsigned char) c); + if (buffer == 0) + return (int) CharPointer_UTF16::getBytesRequiredFor (text); - while (--numExtraValues >= 0 && i < (size_t) bufferSizeBytes) - { - const char nextByte = buffer[i]; + return CharPointer_UTF16 (buffer).writeWithDestByteLimit (text, maxBufferSizeBytes); +} - if ((nextByte & 0xc0) != 0x80) - { - n = c; // reset to original value if the input is invalid. - break; - } +int String::getNumBytesAsUTF8() const throw() +{ + return (int) CharPointer_UTF8::getBytesRequiredFor (text); +} - n <<= 6; - n |= (nextByte & 0x3f); - ++i; - } +const String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) +{ + if (buffer == 0) + return empty; - *dest++ = (juce_wchar) n; - } - else - { - *dest++ = (juce_wchar) c; - } - } + const int len = (int) (bufferSizeBytes >= 0 ? CharPointer_UTF8 (buffer).lengthUpTo (bufferSizeBytes) + : CharPointer_UTF8 (buffer).length()); - *dest = 0; + String result (Preallocation (len + 1)); + CharPointerType (result.text).writeWithCharLimit (CharPointer_UTF8 (buffer), len + 1); return result; } //============================================================================== const char* String::toCString() const { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 return toUTF8(); #else if (isEmpty()) - return reinterpret_cast (text); + return reinterpret_cast (text.getAddress()); const int len = getNumBytesAsCString(); char* const extraSpace = static_cast (createSpaceAtEndOfBuffer (len + 1)); @@ -2046,7 +2106,7 @@ const char* String::toCString() const int String::getNumBytesAsCString() const throw() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 return getNumBytesAsUTF8(); #else return (int) wcstombs (0, text, 0); @@ -2055,7 +2115,7 @@ int String::getNumBytesAsCString() const throw() int String::copyToCString (char* destBuffer, const int maxBufferSizeBytes) const throw() { - #if JUCE_ANDROID + #if JUCE_NATIVE_WCHAR_IS_NOT_UTF32 return copyToUTF8 (destBuffer, maxBufferSizeBytes); #else const int numBytes = (int) wcstombs (destBuffer, text, maxBufferSizeBytes); @@ -2071,15 +2131,6 @@ int String::copyToCString (char* destBuffer, const int maxBufferSizeBytes) const #pragma warning (pop) #endif -//============================================================================== -void String::copyToUnicode (juce_wchar* const destBuffer, const int maxCharsToCopy) const throw() -{ - jassert (destBuffer != 0 && maxCharsToCopy >= 0); - - if (destBuffer != 0 && maxCharsToCopy >= 0) - StringHolder::copyChars (destBuffer, text, jmin (maxCharsToCopy, length())); -} - //============================================================================== String::Concatenator::Concatenator (String& stringToAppendTo) : result (stringToAppendTo), @@ -2098,7 +2149,7 @@ void String::Concatenator::append (const String& s) if (len > 0) { result.preallocateStorage (nextIndex + len); - s.copyToUnicode (static_cast (result) + nextIndex, len); + CharPointerType (result.text + nextIndex).writeAll (s.text); nextIndex += len; } } @@ -2110,12 +2161,58 @@ void String::Concatenator::append (const String& s) #include "../utilities/juce_UnitTest.h" #include "../maths/juce_Random.h" +#include "juce_StringArray.h" class StringTests : public UnitTest { public: StringTests() : UnitTest ("String class") {} + template + struct TestUTFConversion + { + static void test (UnitTest& test) + { + String s (createRandomWideCharString()); + + typename CharPointerType::CharType buffer [300]; + + memset (buffer, 0xff, sizeof (buffer)); + CharPointerType (buffer).writeAll (s.toUTF32()); + test.expectEquals (String (CharPointerType (buffer)), s); + + memset (buffer, 0xff, sizeof (buffer)); + CharPointerType (buffer).writeAll (s.toUTF16()); + test.expectEquals (String (CharPointerType (buffer)), s); + + memset (buffer, 0xff, sizeof (buffer)); + CharPointerType (buffer).writeAll (s.toUTF8()); + test.expectEquals (String (CharPointerType (buffer)), s); + } + }; + + static const String createRandomWideCharString() + { + juce_wchar buffer [50]; + zerostruct (buffer); + + for (int i = 0; i < numElementsInArray (buffer) - 1; ++i) + { + if (Random::getSystemRandom().nextBool()) + { + do + { + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); + } + while (buffer[i] >= 0xd800 && buffer[i] <= 0xdfff); // (these code-points are illegal in UTF-16) + } + else + buffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0xff)); + } + + return buffer; + } + void runTest() { { @@ -2340,35 +2437,26 @@ public: } { - beginTest ("UTF8"); + beginTest ("UTF conversions"); - String s ("word word2 word3"); - - { - char buffer [100]; - memset (buffer, 0xff, sizeof (buffer)); - s.copyToUTF8 (buffer, 100); - expectEquals (String::fromUTF8 (buffer, 100), s); - - juce_wchar bufferUnicode [100]; - memset (bufferUnicode, 0xff, sizeof (bufferUnicode)); - s.copyToUnicode (bufferUnicode, 100); - expectEquals (String (bufferUnicode, 100), s); - } - - { - juce_wchar wideBuffer [50]; - zerostruct (wideBuffer); - - for (int i = 0; i < numElementsInArray (wideBuffer) - 1; ++i) - wideBuffer[i] = (juce_wchar) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1)); + TestUTFConversion ::test (*this); + TestUTFConversion ::test (*this); + TestUTFConversion ::test (*this); + } - String wide (wideBuffer); - expect (wide == (const juce_wchar*) wideBuffer); - expect (wide.length() == numElementsInArray (wideBuffer) - 1); - expect (String::fromUTF8 (wide.toUTF8()) == wide); - expect (String::fromUTF8 (wide.toUTF8()) == wideBuffer); - } + { + beginTest ("StringArray"); + + StringArray s; + for (int i = 5; --i >= 0;) + s.add (String (i)); + + expectEquals (s.joinIntoString ("-"), String ("4-3-2-1-0")); + s.remove (2); + expectEquals (s.joinIntoString ("--"), String ("4--3--1--0")); + expectEquals (s.joinIntoString (String::empty), String ("4310")); + s.clear(); + expectEquals (s.joinIntoString ("x"), String::empty); } } }; diff --git a/src/text/juce_String.h b/src/text/juce_String.h index 871e19326e..1cdf9dc477 100644 --- a/src/text/juce_String.h +++ b/src/text/juce_String.h @@ -33,6 +33,7 @@ #pragma warning (disable: 4514 4996) #endif +#include "../memory/juce_Atomic.h" #include "juce_CharPointer_UTF8.h" #include "juce_CharPointer_UTF16.h" #include "juce_CharPointer_UTF32.h" @@ -89,6 +90,26 @@ public: */ String (const juce_wchar* unicodeText, size_t maxChars); + /** Creates a string from a UTF-8 character string */ + String (const CharPointer_UTF8& text); + + /** Creates a string from a UTF-16 character string */ + String (const CharPointer_UTF16& text); + + /** Creates a string from a UTF-32 character string */ + String (const CharPointer_UTF32& text); + + /** Creates a string from a UTF-32 character string */ + String (const CharPointer_UTF32& text, size_t maxChars); + + #if JUCE_WINDOWS + /** 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); @@ -103,6 +124,9 @@ public: */ static const String empty; + /** This is the character encoding type used internally to store the string. */ + typedef CharPointer_UTF32 CharPointerType; + //============================================================================== /** Generates a probably-unique 32-bit hashcode from this string. */ int hashCode() const throw(); @@ -127,15 +151,63 @@ public: String& operator+= (char characterToAppend); /** Appends a character at the end of this string. */ String& operator+= (juce_wchar characterToAppend); + #if JUCE_WINDOWS + /** Appends a character at the end of this string. */ + String& operator+= (wchar_t characterToAppend); + /** Appends another string at the end of this one. */ + String& operator+= (const wchar_t* textToAppend); + #endif /** Appends a decimal number at the end of this string. */ String& operator+= (int numberToAppend); - /** Appends a string at the end of this one. + /** Appends a string to the end of this one. + + @param textToAppend the string to add + @param maxCharsToTake the maximum number of characters to take from the string passed in + */ + void append (const String& textToAppend, size_t maxCharsToTake); + + /** Appends a string to the end of this one. @param textToAppend the string to add @param maxCharsToTake the maximum number of characters to take from the string passed in */ - void append (const juce_wchar* textToAppend, int maxCharsToTake); + template + void appendCharPointer (const CharPointer& textToAppend, size_t maxCharsToTake) + { + if (textToAppend.getAddress() != 0) + { + const size_t numExtraChars = textToAppend.lengthUpTo (maxCharsToTake); + + if (numExtraChars > 0) + { + const int oldLen = length(); + preallocateStorage (oldLen + numExtraChars); + CharPointerType (text + oldLen).writeWithCharLimit (textToAppend, (int) (numExtraChars + 1)); + } + } + } + + /** Appends a string to the end of this one. + + @param textToAppend the string to add + @param maxCharsToTake the maximum number of characters to take from the string passed in + */ + template + void appendCharPointer (const CharPointer& textToAppend) + { + if (textToAppend.getAddress() != 0) + { + const size_t numExtraChars = textToAppend.length(); + + if (numExtraChars > 0) + { + const int oldLen = length(); + preallocateStorage (oldLen + numExtraChars); + CharPointerType (text + oldLen).writeAll (textToAppend); + } + } + } //============================================================================== // Comparison methods.. @@ -915,7 +987,7 @@ public: that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ - inline operator const juce_wchar*() const throw() { return text; } + inline operator const juce_wchar*() const throw() { return text.getAddress(); } //============================================================================== /** Returns a unicode version of this string. @@ -924,21 +996,55 @@ public: that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ - inline operator juce_wchar*() throw() { return text; } + inline operator juce_wchar*() throw() { return text.getAddress(); } //============================================================================== + /** Returns the character pointer currently being used to store 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 be deleted whenever the + string changes. + */ + inline const CharPointerType& getCharPointer() const throw() { return text; } + /** Returns a pointer to a UTF-8 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 be deleted whenever the string changes. - @see getNumBytesAsUTF8, fromUTF8, copyToUTF8, toCString + To find out how many bytes you need to store this string as UTF-8, you can call + CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer()) + + @see getCharPointer, toUTF16, toUTF32 */ - const char* toUTF8() const; + const CharPointer_UTF8 toUTF8() const; - /** Creates a String from a UTF-8 encoded buffer. + /** Returns a pointer to a UTF-32 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 be deleted whenever the + string changes. + + To find out how many bytes you need to store this string as UTF-16, you can call + CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer()) + + @see getCharPointer, toUTF8, toUTF32 + */ + CharPointer_UTF16 toUTF16() const; + + /** Returns a pointer to a UTF-32 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 be deleted whenever the + string changes. + + @see getCharPointer, toUTF8, toUTF16 + */ + inline CharPointer_UTF32 toUTF32() const throw() { return text; } + + //============================================================================== + /** Creates a String from a UTF-8 encoded buffer. If the size is < 0, it'll keep reading until it hits a zero. */ static const String fromUTF8 (const char* utf8buffer, int bufferSizeBytes = -1); @@ -949,20 +1055,40 @@ public: */ int getNumBytesAsUTF8() const throw(); + //============================================================================== /** Copies the string to a buffer as UTF-8 characters. Returns the number of bytes copied to the buffer, including the terminating null character. - @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. + To find out how many bytes you need to store this string as UTF-8, you can call + CharPointer_UTF8::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. + @see CharPointer_UTF8::writeWithDestByteLimit + */ + int copyToUTF8 (CharPointer_UTF8::CharType* destBuffer, int maxBufferSizeBytes) const throw(); + + /** Copies the string to a buffer as UTF-16 characters. + + Returns the number of bytes copied to the buffer, including the terminating null + character. + + To find out how many bytes you need to store this string as UTF-16, you can call + CharPointer_UTF16::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. + @see CharPointer_UTF16::writeWithDestByteLimit */ - int copyToUTF8 (char* destBuffer, int maxBufferSizeBytes) const throw(); + 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. @@ -977,6 +1103,7 @@ public: /** 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(); @@ -992,16 +1119,6 @@ public: */ int copyToCString (char* destBuffer, int maxBufferSizeBytes) const throw(); - //============================================================================== - /** Copies the string to a unicode buffer. - - @param destBuffer the place to copy it to - @param maxCharsToCopy the maximum number of characters to copy to the buffer, - NOT including the trailing zero, so this shouldn't be - larger than the size of your destination buffer - 1 - */ - void copyToUnicode (juce_wchar* destBuffer, int maxCharsToCopy) const throw(); - //============================================================================== /** Increases the string's internally allocated storage. @@ -1052,7 +1169,7 @@ public: private: //============================================================================== - juce_wchar* text; + CharPointerType text; //============================================================================== struct Preallocation @@ -1065,8 +1182,9 @@ private: explicit String (const Preallocation&); String (const String& stringToCopy, size_t charsToAllocate); - void createInternal (const juce_wchar* text, size_t numChars); - void appendInternal (const juce_wchar* text, int numExtraChars); + void appendFixedLength (const juce_wchar* text, int numExtraChars); + + void enlarge (size_t newTotalNumChars); void* createSpaceAtEndOfBuffer (size_t numExtraBytes) const; // This private cast operator should prevent strings being accidentally cast @@ -1095,6 +1213,14 @@ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const juce_wchar JUCE_API const String JUCE_CALLTYPE operator+ (String string1, char characterToAppend); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, juce_wchar characterToAppend); +#if JUCE_WINDOWS +/** Concatenates two strings. */ +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, wchar_t characterToAppend); +/** Concatenates two strings. */ +JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const wchar_t* string2); +/** Concatenates two strings. */ +JUCE_API const String JUCE_CALLTYPE operator+ (const wchar_t* string1, const String& string2); +#endif //============================================================================== /** Appends a character at the end of a string. */ @@ -1127,12 +1253,24 @@ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const char* strin /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const juce_wchar* string2) throw(); /** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF8& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF16& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF32& string2) throw(); +/** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const char* string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const juce_wchar* string2) throw(); /** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF8& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF16& string2) throw(); +/** Case-sensitive comparison of two strings. */ +JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF32& string2) throw(); +/** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator< (const String& string1, const String& string2) throw(); @@ -1148,7 +1286,7 @@ JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& str template JUCE_API std::basic_ostream & JUCE_CALLTYPE operator<< (std::basic_ostream & stream, const String& stringToWrite) { - return stream << stringToWrite.toUTF8(); + return stream << stringToWrite.toUTF8().getAddress(); } /** Writes a string to an OutputStream as UTF8. */ diff --git a/src/text/juce_StringArray.cpp b/src/text/juce_StringArray.cpp index 3b65941ce6..1fee7b63d6 100644 --- a/src/text/juce_StringArray.cpp +++ b/src/text/juce_StringArray.cpp @@ -317,27 +317,20 @@ const String StringArray::joinIntoString (const String& separator, int start, in String result; result.preallocateStorage (charsNeeded); - juce_wchar* dest = result; + String::CharPointerType dest (result.getCharPointer()); while (start < last) { const String& s = strings.getReference (start); - const int len = s.length(); - if (len > 0) - { - s.copyToUnicode (dest, len); - dest += len; - } + if (! s.isEmpty()) + dest.writeAll (s.getCharPointer()); if (++start < last && separatorLen > 0) - { - separator.copyToUnicode (dest, separatorLen); - dest += separatorLen; - } + dest.writeAll (separator.getCharPointer()); } - *dest = 0; + dest.writeNull(); return result; } diff --git a/src/text/juce_XmlDocument.cpp b/src/text/juce_XmlDocument.cpp index 5b9c31ebd3..f1e8868a9d 100644 --- a/src/text/juce_XmlDocument.cpp +++ b/src/text/juce_XmlDocument.cpp @@ -85,8 +85,8 @@ namespace XmlIdentifierChars { static const uint32 legalChars[] = { 0, 0x7ff6000, 0x87fffffe, 0x7fffffe, 0 }; - return (c < numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (1 << (c & 31))) != 0) - : isIdentifierCharSlow (c); + return ((int) c < (int) numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (1 << (c & 31))) != 0) + : isIdentifierCharSlow (c); } /*static void generateIdentifierCharConstants()