| @@ -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)); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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; | |||
| @@ -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"); | |||
| @@ -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(); | |||
| @@ -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(); | |||
| @@ -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; | |||
| @@ -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(); | |||
| @@ -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"); | |||
| @@ -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")) | |||
| { | |||
| @@ -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")); | |||
| @@ -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 {}; | |||
| @@ -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) | |||
| @@ -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)); | |||
| } | |||
| //============================================================================== | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -130,7 +130,7 @@ namespace juce | |||
| auto xmlString = animalsList.toString(); | |||
| @endcode | |||
| @see XmlDocument | |||
| @see parseXML, parseXMLIfTagMatches, XmlDocument | |||
| @tags{Core} | |||
| */ | |||
| @@ -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]); | |||
| @@ -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; | |||
| @@ -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 {}; | |||
| } | |||