Browse Source

Added handy new function parseXMLIfTagMatches(), and refactored a lot of old code that was parsing XML in a more clunky way

tags/2021-05-28
jules 6 years ago
parent
commit
0fb8c8e82a
20 changed files with 135 additions and 153 deletions
  1. +1
    -3
      examples/Plugins/AudioPluginDemo.h
  2. +1
    -3
      examples/Plugins/InterAppAudioEffectPluginDemo.h
  3. +36
    -40
      examples/Utilities/AnalyticsCollectionDemo.h
  4. +13
    -13
      extras/AudioPluginHost/Source/Filters/FilterGraph.cpp
  5. +5
    -7
      extras/Projucer/Source/Application/jucer_ProjucerAnalytics.cpp
  6. +1
    -4
      extras/Projucer/Source/ComponentEditor/jucer_ComponentLayout.cpp
  7. +3
    -5
      extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp
  8. +1
    -4
      extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp
  9. +1
    -1
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h
  10. +1
    -2
      extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h
  11. +1
    -3
      modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  12. +2
    -2
      modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
  13. +1
    -1
      modules/juce_core/containers/juce_PropertySet.cpp
  14. +1
    -1
      modules/juce_core/network/juce_URL.cpp
  15. +25
    -8
      modules/juce_core/xml/juce_XmlDocument.cpp
  16. +24
    -6
      modules/juce_core/xml/juce_XmlDocument.h
  17. +1
    -1
      modules/juce_core/xml/juce_XmlElement.h
  18. +12
    -27
      modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp
  19. +2
    -8
      modules/juce_gui_basics/drawables/juce_Drawable.cpp
  20. +3
    -14
      modules/juce_gui_basics/drawables/juce_SVGParser.cpp

+ 1
- 3
examples/Plugins/AudioPluginDemo.h View File

@@ -293,9 +293,7 @@ public:
{
// Restore our plug-in's state from the xml representation stored in the above
// method.
std::unique_ptr<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
if (xmlState.get() != nullptr)
if (auto xmlState = getXmlFromBinary (data, sizeInBytes))
state.replaceState (ValueTree::fromXml (*xmlState));
}


+ 1
- 3
examples/Plugins/InterAppAudioEffectPluginDemo.h View File

@@ -236,9 +236,7 @@ public:
void setStateInformation (const void* data, int sizeInBytes) override
{
auto xmlState = std::unique_ptr<XmlElement> (getXmlFromBinary (data, sizeInBytes));
if (xmlState.get() != nullptr)
if (auto xmlState = getXmlFromBinary (data, sizeInBytes))
if (xmlState->hasTagName (parameters.state.getType()))
parameters.state = ValueTree::fromXml (*xmlState);
}


+ 36
- 40
examples/Utilities/AnalyticsCollectionDemo.h View File

@@ -212,11 +212,10 @@ private:
// a binary format may be more suitable if it is faster - remember that this
// method is called on app shutdown so it needs to complete quickly!
XmlDocument previouslySavedEvents (savedEventsFile);
std::unique_ptr<XmlElement> xml (previouslySavedEvents.getDocumentElement());
auto xml = parseXMLIfTagMatches (savedEventsFile, "events");
if (xml.get() == nullptr || xml->getTagName() != "events")
xml.reset (new XmlElement ("events"));
if (xml == nullptr)
xml = std::make_unique<XmlElement> ("events");
for (auto& event : eventsToSave)
{
@@ -248,45 +247,42 @@ private:
void restoreUnloggedEvents (std::deque<AnalyticsEvent>& restoredEventQueue) override
{
XmlDocument savedEvents (savedEventsFile);
std::unique_ptr<XmlElement> xml (savedEvents.getDocumentElement());
if (xml.get() == nullptr || xml->getTagName() != "events")
return;
if (auto xml = parseXMLIfTagMatches (savedEventsFile, "events"))
{
auto numEvents = xml->getNumChildElements();
auto numEvents = xml->getNumChildElements();
for (auto iEvent = 0; iEvent < numEvents; ++iEvent)
{
auto* xmlEvent = xml->getChildElement (iEvent);
StringPairArray parameters;
auto* xmlParameters = xmlEvent->getChildByName ("parameters");
auto numParameters = xmlParameters->getNumAttributes();
for (auto iParam = 0; iParam < numParameters; ++iParam)
parameters.set (xmlParameters->getAttributeName (iParam),
xmlParameters->getAttributeValue (iParam));
StringPairArray userProperties;
auto* xmlUserProperties = xmlEvent->getChildByName ("user_properties");
auto numUserProperties = xmlUserProperties->getNumAttributes();
for (auto iProp = 0; iProp < numUserProperties; ++iProp)
userProperties.set (xmlUserProperties->getAttributeName (iProp),
xmlUserProperties->getAttributeValue (iProp));
restoredEventQueue.push_back ({
xmlEvent->getStringAttribute ("name"),
xmlEvent->getIntAttribute ("type"),
static_cast<uint32> (xmlEvent->getIntAttribute ("timestamp")),
parameters,
xmlEvent->getStringAttribute ("user_id"),
userProperties
});
}
for (auto iEvent = 0; iEvent < numEvents; ++iEvent)
{
auto* xmlEvent = xml->getChildElement (iEvent);
StringPairArray parameters;
auto* xmlParameters = xmlEvent->getChildByName ("parameters");
auto numParameters = xmlParameters->getNumAttributes();
for (auto iParam = 0; iParam < numParameters; ++iParam)
parameters.set (xmlParameters->getAttributeName (iParam),
xmlParameters->getAttributeValue (iParam));
StringPairArray userProperties;
auto* xmlUserProperties = xmlEvent->getChildByName ("user_properties");
auto numUserProperties = xmlUserProperties->getNumAttributes();
for (auto iProp = 0; iProp < numUserProperties; ++iProp)
userProperties.set (xmlUserProperties->getAttributeName (iProp),
xmlUserProperties->getAttributeValue (iProp));
restoredEventQueue.push_back ({
xmlEvent->getStringAttribute ("name"),
xmlEvent->getIntAttribute ("type"),
static_cast<uint32> (xmlEvent->getIntAttribute ("timestamp")),
parameters,
xmlEvent->getStringAttribute ("user_id"),
userProperties
});
savedEventsFile.deleteFile();
}
savedEventsFile.deleteFile();
}
const int initialPeriodMs = 1000;


+ 13
- 13
extras/AudioPluginHost/Source/Filters/FilterGraph.cpp View File

@@ -221,26 +221,26 @@ void FilterGraph::newDocument()
Result FilterGraph::loadDocument (const File& file)
{
XmlDocument doc (file);
std::unique_ptr<XmlElement> xml (doc.getDocumentElement());
if (xml == nullptr || ! xml->hasTagName ("FILTERGRAPH"))
return Result::fail ("Not a valid filter graph file");
if (auto xml = parseXMLIfTagMatches (file, "FILTERGRAPH"))
{
graph.removeChangeListener (this);
restoreFromXml (*xml);
graph.removeChangeListener (this);
restoreFromXml (*xml);
MessageManager::callAsync ([this]
{
setChangedFlag (false);
graph.addChangeListener (this);
});
MessageManager::callAsync ([this] () {
setChangedFlag (false);
graph.addChangeListener (this);
} );
return Result::ok();
}
return Result::ok();
return Result::fail ("Not a valid filter graph file");
}
Result FilterGraph::saveDocument (const File& file)
{
std::unique_ptr<XmlElement> xml (createXml());
auto xml = createXml();
if (! xml->writeTo (file, {}))
return Result::fail ("Couldn't write to the file");


+ 5
- 7
extras/Projucer/Source/Application/jucer_ProjucerAnalytics.cpp View File

@@ -178,11 +178,10 @@ void ProjucerAnalyticsDestination::stopLoggingEvents()
//==============================================================================
void ProjucerAnalyticsDestination::saveUnloggedEvents (const std::deque<AnalyticsEvent>& eventsToSave)
{
XmlDocument previouslySavedEvents (savedEventsFile);
std::unique_ptr<XmlElement> xml (previouslySavedEvents.getDocumentElement());
auto xml = parseXMLIfTagMatches (savedEventsFile, "events");
if (xml.get() == nullptr || xml->getTagName() != "events")
xml.reset (new XmlElement ("events"));
if (xml == nullptr)
xml = std::make_unique<XmlElement> ("events");
for (auto& event : eventsToSave)
{
@@ -214,10 +213,9 @@ void ProjucerAnalyticsDestination::saveUnloggedEvents (const std::deque<Analytic
void ProjucerAnalyticsDestination::restoreUnloggedEvents (std::deque<AnalyticsEvent>& restoredEventQueue)
{
XmlDocument savedEvents (savedEventsFile);
std::unique_ptr<XmlElement> xml (savedEvents.getDocumentElement());
auto xml = parseXMLIfTagMatches (savedEventsFile, "events");
if (xml.get() == nullptr || xml->getTagName() != "events")
if (xml == nullptr)
return;
auto numEvents = xml->getNumChildElements();


+ 1
- 4
extras/Projucer/Source/ComponentEditor/jucer_ComponentLayout.cpp View File

@@ -271,10 +271,7 @@ void ComponentLayout::copySelectedToClipboard()
void ComponentLayout::paste()
{
XmlDocument clip (SystemClipboard::getTextFromClipboard());
std::unique_ptr<XmlElement> doc (clip.getDocumentElement());
if (doc != nullptr && doc->hasTagName (clipboardXmlTag))
if (auto doc = parseXMLIfTagMatches (SystemClipboard::getTextFromClipboard(), clipboardXmlTag))
{
selected.deselectAll();


+ 3
- 5
extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp View File

@@ -624,16 +624,14 @@ void JucerDocument::extractCustomPaintSnippetsFromCppFile (const String& cppCont
std::unique_ptr<XmlElement> JucerDocument::pullMetaDataFromCppFile (const String& cpp)
{
auto lines = StringArray::fromLines (cpp);
const int startLine = indexOfLineStartingWith (lines, "BEGIN_JUCER_METADATA", 0);
auto startLine = indexOfLineStartingWith (lines, "BEGIN_JUCER_METADATA", 0);
if (startLine > 0)
{
const int endLine = indexOfLineStartingWith (lines, "END_JUCER_METADATA", startLine);
auto endLine = indexOfLineStartingWith (lines, "END_JUCER_METADATA", startLine);
if (endLine > startLine)
return XmlDocument::parse (lines.joinIntoString ("\n", startLine + 1,
endLine - startLine - 1));
return parseXML (lines.joinIntoString ("\n", startLine + 1, endLine - startLine - 1));
}
return nullptr;


+ 1
- 4
extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp View File

@@ -302,10 +302,7 @@ void PaintRoutine::copySelectedToClipboard()
void PaintRoutine::paste()
{
XmlDocument clip (SystemClipboard::getTextFromClipboard());
std::unique_ptr<XmlElement> doc (clip.getDocumentElement());
if (doc != nullptr && doc->hasTagName (clipboardXmlTag))
if (auto doc = parseXMLIfTagMatches (SystemClipboard::getTextFromClipboard(), clipboardXmlTag))
{
selectedElements.deselectAll();
selectedPoints.deselectAll();


+ 1
- 1
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Android.h View File

@@ -1543,7 +1543,7 @@ private:
std::unique_ptr<XmlElement> createManifestElement() const
{
auto manifest = XmlDocument::parse (androidManifestCustomXmlElements.get());
auto manifest = parseXML (androidManifestCustomXmlElements.get());
if (manifest == nullptr)
manifest = std::make_unique<XmlElement> ("manifest");


+ 1
- 2
extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_CLion.h View File

@@ -1013,9 +1013,8 @@ private:
if (targetAttributeKeys.contains ("INFOPLIST_FILE"))
{
auto plistFile = exporter.getTargetFolder().getChildFile (targetAttributes["INFOPLIST_FILE"]);
XmlDocument infoPlistData (plistFile);
if (auto plist = std::unique_ptr<XmlElement> (infoPlistData.getDocumentElement()))
if (auto plist = parseXML (plistFile))
{
if (auto* dict = plist->getChildByName ("dict"))
{


+ 1
- 3
modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -2292,9 +2292,7 @@ public:
void setStateInformation (const void* data, int sizeInBytes) override
{
std::unique_ptr<XmlElement> head (AudioProcessor::getXmlFromBinary (data, sizeInBytes));
if (head != nullptr)
if (auto head = AudioProcessor::getXmlFromBinary (data, sizeInBytes))
{
auto componentStream (createMemoryStreamForState (*head, "IComponent"));


+ 2
- 2
modules/juce_audio_processors/processors/juce_AudioProcessor.cpp View File

@@ -1121,8 +1121,8 @@ std::unique_ptr<XmlElement> AudioProcessor::getXmlFromBinary (const void* data,
auto stringLength = (int) ByteOrder::littleEndianInt (addBytesToPointer (data, 4));
if (stringLength > 0)
return XmlDocument::parse (String::fromUTF8 (static_cast<const char*> (data) + 8,
jmin ((sizeInBytes - 8), stringLength)));
return parseXML (String::fromUTF8 (static_cast<const char*> (data) + 8,
jmin ((sizeInBytes - 8), stringLength)));
}
return {};


+ 1
- 1
modules/juce_core/containers/juce_PropertySet.cpp View File

@@ -112,7 +112,7 @@ bool PropertySet::getBoolValue (StringRef keyName, bool defaultValue) const noex
std::unique_ptr<XmlElement> PropertySet::getXmlValue (StringRef keyName) const
{
return XmlDocument::parse (getValue (keyName));
return parseXML (getValue (keyName));
}
void PropertySet::setValue (const String& keyName, const var& v)


+ 1
- 1
modules/juce_core/network/juce_URL.cpp View File

@@ -790,7 +790,7 @@ String URL::readEntireTextStream (bool usePostCommand) const
std::unique_ptr<XmlElement> URL::readEntireXmlStream (bool usePostCommand) const
{
return XmlDocument::parse (readEntireTextStream (usePostCommand));
return parseXML (readEntireTextStream (usePostCommand));
}
//==============================================================================


+ 25
- 8
modules/juce_core/xml/juce_XmlDocument.cpp View File

@@ -30,24 +30,32 @@ XmlDocument::~XmlDocument() {}
std::unique_ptr<XmlElement> XmlDocument::parse (const File& file)
{
XmlDocument doc (file);
return doc.getDocumentElement();
return XmlDocument (file).getDocumentElement();
}
std::unique_ptr<XmlElement> XmlDocument::parse (const String& xmlData)
std::unique_ptr<XmlElement> XmlDocument::parse (const String& textToParse)
{
XmlDocument doc (xmlData);
return doc.getDocumentElement();
return XmlDocument (textToParse).getDocumentElement();
}
std::unique_ptr<XmlElement> parseXML (const String& textToParse)
{
return std::unique_ptr<XmlElement> (XmlDocument::parse (textToParse));
return XmlDocument (textToParse).getDocumentElement();
}
std::unique_ptr<XmlElement> parseXML (const File& fileToParse)
std::unique_ptr<XmlElement> parseXML (const File& file)
{
return std::unique_ptr<XmlElement> (XmlDocument::parse (fileToParse));
return XmlDocument (file).getDocumentElement();
}
std::unique_ptr<XmlElement> parseXMLIfTagMatches (const String& textToParse, StringRef requiredTag)
{
return XmlDocument (textToParse).getDocumentElementIfTagMatches (requiredTag);
}
std::unique_ptr<XmlElement> parseXMLIfTagMatches (const File& file, StringRef requiredTag)
{
return XmlDocument (file).getDocumentElementIfTagMatches (requiredTag);
}
void XmlDocument::setInputSource (InputSource* newSource) noexcept
@@ -139,6 +147,15 @@ std::unique_ptr<XmlElement> XmlDocument::getDocumentElement (const bool onlyRead
return parseDocumentElement (originalText.getCharPointer(), onlyReadOuterDocumentElement);
}
std::unique_ptr<XmlElement> XmlDocument::getDocumentElementIfTagMatches (StringRef requiredTag)
{
if (auto xml = getDocumentElement (true))
if (xml->hasTagName (requiredTag))
return getDocumentElement (false);
return {};
}
const String& XmlDocument::getLastParseError() const noexcept
{
return lastError;


+ 24
- 6
modules/juce_core/xml/juce_XmlDocument.h View File

@@ -98,12 +98,17 @@ public:
tag, without having to parse the entire file
@returns a new XmlElement which the caller will need to delete, or null if
there was an error.
@see getLastParseError
@see getLastParseError, getDocumentElementIfTagMatches
*/
std::unique_ptr<XmlElement> getDocumentElement (bool onlyReadOuterDocumentElement = false);
/** Returns the parsing error that occurred the last time getDocumentElement was called.
/** Does an inexpensive check to see whether the outer element has the given tag name, and
then does a full parse if it matches.
If the tag is different, or the XML parse fails, this will return nullptr.
*/
std::unique_ptr<XmlElement> getDocumentElementIfTagMatches (StringRef requiredTag);
/** Returns the parsing error that occurred the last time getDocumentElement was called.
@returns the error, or an empty string if there was no error.
*/
const String& getLastParseError() const noexcept;
@@ -178,18 +183,31 @@ private:
//==============================================================================
/** Attempts to parse some XML text, returning a new XmlElement if it was valid.
If the parse fails, this will return a nullptr - if you need more information about
errors or more parsing options, see the XmlDocument instead.
@see XmlDocument
errors or more parsing options, see the XmlDocument class instead.
@see XmlDocument, parseXMLIfTagMatches
*/
std::unique_ptr<XmlElement> parseXML (const String& textToParse);
/** Attempts to parse some XML text, returning a new XmlElement if it was valid.
If the parse fails, this will return a nullptr - if you need more information about
errors or more parsing options, see the XmlDocument instead.
@see XmlDocument
errors or more parsing options, see the XmlDocument class instead.
@see XmlDocument, parseXMLIfTagMatches
*/
std::unique_ptr<XmlElement> parseXML (const File& fileToParse);
/** Does an inexpensive check to see whether the top-level element has the given tag
name, and if that's true, does a full parse and returns the result.
If the outer tag doesn't match, or the XML has errors, this will return nullptr;
@see parseXML
*/
std::unique_ptr<XmlElement> parseXMLIfTagMatches (const String& textToParse, StringRef requiredTag);
/** Does an inexpensive check to see whether the top-level element has the given tag
name, and if that's true, does a full parse and returns the result.
If the outer tag doesn't match, or the XML has errors, this will return nullptr;
@see parseXML
*/
std::unique_ptr<XmlElement> parseXMLIfTagMatches (const File& fileToParse, StringRef requiredTag);
} // namespace juce

+ 1
- 1
modules/juce_core/xml/juce_XmlElement.h View File

@@ -130,7 +130,7 @@ namespace juce
auto xmlString = animalsList.toString();
@endcode
@see XmlDocument
@see parseXML, parseXMLIfTagMatches, XmlDocument
@tags{Core}
*/


+ 12
- 27
modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp View File

@@ -186,35 +186,20 @@ bool PropertiesFile::save()
bool PropertiesFile::loadAsXml()
{
XmlDocument parser (file);
if (auto doc = parser.getDocumentElement (true))
if (auto doc = parseXMLIfTagMatches (file, PropertyFileConstants::fileTag))
{
if (doc->hasTagName (PropertyFileConstants::fileTag))
forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag)
{
doc = parser.getDocumentElement();
if (doc != nullptr)
{
forEachXmlChildElementWithTagName (*doc, e, PropertyFileConstants::valueTag)
{
auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute);
if (name.isNotEmpty())
getAllProperties().set (name,
e->getFirstChildElement() != nullptr
? e->getFirstChildElement()->toString (XmlElement::TextFormat().singleLine().withoutHeader())
: e->getStringAttribute (PropertyFileConstants::valueAttribute));
}
return true;
}
// must be a pretty broken XML file we're trying to parse here,
// or a sign that this object needs an InterProcessLock,
// or just a failure reading the file. This last reason is why
// we don't jassertfalse here.
auto name = e->getStringAttribute (PropertyFileConstants::nameAttribute);
if (name.isNotEmpty())
getAllProperties().set (name,
e->getFirstChildElement() != nullptr
? e->getFirstChildElement()->toString (XmlElement::TextFormat().singleLine().withoutHeader())
: e->getStringAttribute (PropertyFileConstants::valueAttribute));
}
return true;
}
return false;
@@ -231,7 +216,7 @@ bool PropertiesFile::saveAsXml()
e->setAttribute (PropertyFileConstants::nameAttribute, props.getAllKeys() [i]);
// if the value seems to contain xml, store it as such..
if (auto childElement = XmlDocument::parse (props.getAllValues() [i]))
if (auto childElement = parseXML (props.getAllValues() [i]))
e->addChildElement (childElement.release());
else
e->setAttribute (PropertyFileConstants::valueAttribute, props.getAllValues() [i]);


+ 2
- 8
modules/juce_gui_basics/drawables/juce_Drawable.cpp View File

@@ -180,14 +180,8 @@ std::unique_ptr<Drawable> Drawable::createFromImageData (const void* data, const
}
else
{
auto asString = String::createStringFromData (data, (int) numBytes);
XmlDocument doc (asString);
std::unique_ptr<XmlElement> outer (doc.getDocumentElement (true));
if (outer != nullptr && outer->hasTagName ("svg"))
if (auto svg = doc.getDocumentElement())
result = Drawable::createFromSVG (*svg);
if (auto svg = parseXMLIfTagMatches (String::createStringFromData (data, (int) numBytes), "svg"))
result = Drawable::createFromSVG (*svg);
}
return result;


+ 3
- 14
modules/juce_gui_basics/drawables/juce_SVGParser.cpp View File

@@ -1702,24 +1702,13 @@ std::unique_ptr<Drawable> Drawable::createFromSVG (const XmlElement& svgDocument
return {};
SVGState state (&svgDocument);
return std::unique_ptr<Drawable> (state.parseSVGElement (SVGState::XmlPath (&svgDocument, nullptr)));
return std::unique_ptr<Drawable> (state.parseSVGElement (SVGState::XmlPath (&svgDocument, {})));
}
std::unique_ptr<Drawable> Drawable::createFromSVGFile (const File& svgFile)
{
XmlDocument doc (svgFile);
if (auto outer = doc.getDocumentElement (true))
{
if (outer->hasTagName ("svg"))
{
if (auto svgDocument = doc.getDocumentElement())
{
SVGState state (svgDocument.get(), svgFile);
return std::unique_ptr<Drawable> (state.parseSVGElement (SVGState::XmlPath (svgDocument.get(), nullptr)));
}
}
}
if (auto xml = parseXMLIfTagMatches (svgFile, "svg"))
return createFromSVG (*xml);
return {};
}


Loading…
Cancel
Save