diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp
index 0481b61ca..68938fb07 100644
--- a/source/backend/engine/CarlaEngine.cpp
+++ b/source/backend/engine/CarlaEngine.cpp
@@ -1537,43 +1537,47 @@ void CarlaEngine::setPluginPeaks(const uint pluginId, float const inPeaks[2], fl
pluginData.outsPeak[1] = outPeaks[1];
}
-void CarlaEngine::saveProjectInternal(juce::MemoryOutputStream& outStrm) const
+void CarlaEngine::saveProjectInternal(juce::MemoryOutputStream& outStream) const
{
- outStrm << "\n";
- outStrm << "\n";
- outStrm << "\n";
+ outStream << "\n";
+ outStream << "\n";
+ outStream << "\n";
const bool isPlugin(std::strcmp(getCurrentDriverName(), "Plugin") == 0);
const EngineOptions& options(pData->options);
+ MemoryOutputStream outSettings(1024);
+
+
// save appropriate engine settings
- outStrm << " \n";
+ outSettings << " \n";
//processMode
//transportMode
- outStrm << " " << bool2str(options.forceStereo) << "\n";
- outStrm << " " << bool2str(options.preferPluginBridges) << "\n";
- outStrm << " " << bool2str(options.preferUiBridges) << "\n";
- outStrm << " " << bool2str(options.uisAlwaysOnTop) << "\n";
+ outSettings << " " << bool2str(options.forceStereo) << "\n";
+ outSettings << " " << bool2str(options.preferPluginBridges) << "\n";
+ outSettings << " " << bool2str(options.preferUiBridges) << "\n";
+ outSettings << " " << bool2str(options.uisAlwaysOnTop) << "\n";
- outStrm << " " << String(options.maxParameters) << "\n";
- outStrm << " " << String(options.uiBridgesTimeout) << "\n";
+ outSettings << " " << String(options.maxParameters) << "\n";
+ outSettings << " " << String(options.uiBridgesTimeout) << "\n";
if (isPlugin)
{
- outStrm << " " << xmlSafeString(options.pathLADSPA, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathDSSI, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathLV2, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathVST, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathVST3, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathAU, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathGIG, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathSF2, true) << "\n";
- outStrm << " " << xmlSafeString(options.pathSFZ, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathLADSPA, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathDSSI, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathLV2, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathVST, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathVST3, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathAU, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathGIG, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathSF2, true) << "\n";
+ outSettings << " " << xmlSafeString(options.pathSFZ, true) << "\n";
}
- outStrm << " \n";
+ outSettings << " \n";
+ outStream << outSettings;
char strBuf[STR_MAX+1];
@@ -1583,17 +1587,20 @@ void CarlaEngine::saveProjectInternal(juce::MemoryOutputStream& outStrm) const
if (plugin != nullptr && plugin->isEnabled())
{
- outStrm << "\n";
+ MemoryOutputStream outPlugin(4096);
+
+ outPlugin << "\n";
strBuf[0] = '\0';
plugin->getRealName(strBuf);
if (strBuf[0] != '\0')
- outStrm << " \n";
+ outPlugin << " \n";
- outStrm << " \n";
- outStrm << plugin->getStateSave().toString();
- outStrm << " \n";
+ outPlugin << " \n";
+ outPlugin << plugin->getStateSave().toString();
+ outPlugin << " \n";
+ outStream << outPlugin;
}
}
@@ -1617,7 +1624,9 @@ void CarlaEngine::saveProjectInternal(juce::MemoryOutputStream& outStrm) const
{
if (const char* const* const patchbayConns = getPatchbayConnections())
{
- outStrm << "\n \n";
+ MemoryOutputStream outPatchbay(2048);
+
+ outPatchbay << "\n \n";
for (int i=0; patchbayConns[i] != nullptr && patchbayConns[i+1] != nullptr; ++i, ++i )
{
@@ -1627,18 +1636,19 @@ void CarlaEngine::saveProjectInternal(juce::MemoryOutputStream& outStrm) const
CARLA_SAFE_ASSERT_CONTINUE(connSource != nullptr && connSource[0] != '\0');
CARLA_SAFE_ASSERT_CONTINUE(connTarget != nullptr && connTarget[0] != '\0');
- outStrm << " \n";
- outStrm << " " << connSource << "\n";
- outStrm << " " << connTarget << "\n";
- outStrm << " \n";
+ outPatchbay << " \n";
+ outPatchbay << " " << connSource << "\n";
+ outPatchbay << " " << connTarget << "\n";
+ outPatchbay << " \n";
}
- outStrm << " \n";
+ outPatchbay << " \n";
+ outStream << outPatchbay;
}
}
#endif
- outStrm << "\n";
+ outStream << "\n";
}
bool CarlaEngine::loadProjectInternal(juce::XmlDocument& xmlDoc)
diff --git a/source/utils/CarlaStateUtils.cpp b/source/utils/CarlaStateUtils.cpp
index 721867f98..923c88dc8 100644
--- a/source/utils/CarlaStateUtils.cpp
+++ b/source/utils/CarlaStateUtils.cpp
@@ -21,6 +21,8 @@
#include "CarlaMathUtils.hpp"
#include "CarlaMIDI.h"
+#include
+
using juce::String;
using juce::XmlElement;
@@ -50,6 +52,51 @@ static String getNewLineSplittedString(const String& string)
return newString;
}
+// -----------------------------------------------------------------------
+// xmlSafeStringFast
+
+/* Based on some code by James Kanze from stackoverflow
+ * https://stackoverflow.com/questions/7724011/in-c-whats-the-fastest-way-to-replace-all-occurrences-of-a-substring-within */
+
+static std::string replaceStdString(const std::string& original, const std::string& before, const std::string& after)
+{
+ std::string::const_iterator current = original.begin(), end = original.end(), next;
+ std::string retval;
+
+ for (; (next = std::search(current, end, before.begin(), before.end())) != end;)
+ {
+ retval.append(current, next);
+ retval.append(after);
+ current = next + static_cast(before.size());
+ }
+ retval.append(current, next);
+ return retval;
+}
+
+static std::string xmlSafeStringFast(const char* const cstring, const bool toXml)
+{
+ std::string string(cstring);
+
+ if (toXml)
+ {
+ string = replaceStdString(string, "&","&");
+ string = replaceStdString(string, "<","<");
+ string = replaceStdString(string, ">",">");
+ string = replaceStdString(string, "'","'");
+ string = replaceStdString(string, "\"",""");
+ }
+ else
+ {
+ string = replaceStdString(string, "<","<");
+ string = replaceStdString(string, ">",">");
+ string = replaceStdString(string, "'","'");
+ string = replaceStdString(string, ""","\"");
+ string = replaceStdString(string, "&","&");
+ }
+
+ return string;
+}
+
// -----------------------------------------------------------------------
// xmlSafeStringCharDup
@@ -577,13 +624,13 @@ String StateSave::toString() const
if (std::strcmp(stateCustomData->type, CUSTOM_DATA_TYPE_CHUNK) == 0 || std::strlen(stateCustomData->value) >= 128)
{
customDataXml << " \n";
- customDataXml << xmlSafeString(stateCustomData->value, true);
+ customDataXml << xmlSafeStringFast(stateCustomData->value, true);
customDataXml << "\n \n";
}
else
{
customDataXml << " ";
- customDataXml << xmlSafeString(stateCustomData->value, true);
+ customDataXml << xmlSafeStringFast(stateCustomData->value, true);
customDataXml << "\n";
}