| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2022 - Raw Material Software Limited
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    The code included in this file is provided under the terms of the ISC license
 -    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 -    To use, copy, modify, and/or distribute this software for any purpose with or
 -    without fee is hereby granted provided that the above copyright notice and
 -    this permission notice appear in all copies.
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - namespace juce
 - {
 - 
 - static bool isValidXmlNameStartCharacter (juce_wchar character) noexcept
 - {
 -     return character == ':'
 -         || character == '_'
 -         || (character >= 'a'     && character <= 'z')
 -         || (character >= 'A'     && character <= 'Z')
 -         || (character >= 0xc0    && character <= 0xd6)
 -         || (character >= 0xd8    && character <= 0xf6)
 -         || (character >= 0xf8    && character <= 0x2ff)
 -         || (character >= 0x370   && character <= 0x37d)
 -         || (character >= 0x37f   && character <= 0x1fff)
 -         || (character >= 0x200c  && character <= 0x200d)
 -         || (character >= 0x2070  && character <= 0x218f)
 -         || (character >= 0x2c00  && character <= 0x2fef)
 -         || (character >= 0x3001  && character <= 0xd7ff)
 -         || (character >= 0xf900  && character <= 0xfdcf)
 -         || (character >= 0xfdf0  && character <= 0xfffd)
 -         || (character >= 0x10000 && character <= 0xeffff);
 - }
 - 
 - static bool isValidXmlNameBodyCharacter (juce_wchar character) noexcept
 - {
 -     return isValidXmlNameStartCharacter (character)
 -         || character == '-'
 -         || character == '.'
 -         || character == 0xb7
 -         || (character >= '0'    && character <= '9')
 -         || (character >= 0x300  && character <= 0x036f)
 -         || (character >= 0x203f && character <= 0x2040);
 - }
 - 
 - XmlElement::XmlAttributeNode::XmlAttributeNode (const XmlAttributeNode& other) noexcept
 -     : name (other.name),
 -       value (other.value)
 - {
 - }
 - 
 - XmlElement::XmlAttributeNode::XmlAttributeNode (const Identifier& n, const String& v) noexcept
 -     : name (n), value (v)
 - {
 -     jassert (isValidXmlName (name));
 - }
 - 
 - XmlElement::XmlAttributeNode::XmlAttributeNode (String::CharPointerType nameStart, String::CharPointerType nameEnd)
 -     : name (nameStart, nameEnd)
 - {
 -     jassert (isValidXmlName (name));
 - }
 - 
 - //==============================================================================
 - XmlElement::XmlElement (const String& tag)
 -     : tagName (StringPool::getGlobalPool().getPooledString (tag))
 - {
 -     jassert (isValidXmlName (tagName));
 - }
 - 
 - XmlElement::XmlElement (const char* tag)
 -     : tagName (StringPool::getGlobalPool().getPooledString (tag))
 - {
 -     jassert (isValidXmlName (tagName));
 - }
 - 
 - XmlElement::XmlElement (StringRef tag)
 -     : tagName (StringPool::getGlobalPool().getPooledString (tag))
 - {
 -     jassert (isValidXmlName (tagName));
 - }
 - 
 - XmlElement::XmlElement (const Identifier& tag)
 -     : tagName (tag.toString())
 - {
 -     jassert (isValidXmlName (tagName));
 - }
 - 
 - XmlElement::XmlElement (String::CharPointerType tagNameStart, String::CharPointerType tagNameEnd)
 -     : tagName (StringPool::getGlobalPool().getPooledString (tagNameStart, tagNameEnd))
 - {
 -     jassert (isValidXmlName (tagName));
 - }
 - 
 - XmlElement::XmlElement (int /*dummy*/) noexcept
 - {
 - }
 - 
 - XmlElement::XmlElement (const XmlElement& other)
 -     : tagName (other.tagName)
 - {
 -     copyChildrenAndAttributesFrom (other);
 - }
 - 
 - XmlElement& XmlElement::operator= (const XmlElement& other)
 - {
 -     if (this != &other)
 -     {
 -         removeAllAttributes();
 -         deleteAllChildElements();
 -         tagName = other.tagName;
 -         copyChildrenAndAttributesFrom (other);
 -     }
 - 
 -     return *this;
 - }
 - 
 - XmlElement::XmlElement (XmlElement&& other) noexcept
 -     : nextListItem      (std::move (other.nextListItem)),
 -       firstChildElement (std::move (other.firstChildElement)),
 -       attributes        (std::move (other.attributes)),
 -       tagName           (std::move (other.tagName))
 - {
 - }
 - 
 - XmlElement& XmlElement::operator= (XmlElement&& other) noexcept
 - {
 -     jassert (this != &other); // hopefully the compiler should make this situation impossible!
 - 
 -     removeAllAttributes();
 -     deleteAllChildElements();
 - 
 -     nextListItem      = std::move (other.nextListItem);
 -     firstChildElement = std::move (other.firstChildElement);
 -     attributes        = std::move (other.attributes);
 -     tagName           = std::move (other.tagName);
 - 
 -     return *this;
 - }
 - 
 - void XmlElement::copyChildrenAndAttributesFrom (const XmlElement& other)
 - {
 -     jassert (firstChildElement.get() == nullptr);
 -     firstChildElement.addCopyOfList (other.firstChildElement);
 - 
 -     jassert (attributes.get() == nullptr);
 -     attributes.addCopyOfList (other.attributes);
 - }
 - 
 - XmlElement::~XmlElement() noexcept
 - {
 -     firstChildElement.deleteAll();
 -     attributes.deleteAll();
 - }
 - 
 - //==============================================================================
 - namespace XmlOutputFunctions
 - {
 -     namespace LegalCharLookupTable
 -     {
 -         template <int c>
 -         struct Bit
 -         {
 -             enum { v = ((c >= 'a' && c <= 'z')
 -                      || (c >= 'A' && c <= 'Z')
 -                      || (c >= '0' && c <= '9')
 -                      || c == ' ' || c == '.'  || c == ',' || c == ';'
 -                      || c == ':' || c == '-'  || c == '(' || c == ')'
 -                      || c == '_' || c == '+'  || c == '=' || c == '?'
 -                      || c == '!' || c == '$'  || c == '#' || c == '@'
 -                      || c == '[' || c == ']'  || c == '/' || c == '|'
 -                      || c == '*' || c == '%'  || c == '~' || c == '{'
 -                      || c == '}' || c == '\'' || c == '\\')
 -                         ? (1 << (c & 7)) : 0 };
 -         };
 - 
 -         template <int tableIndex>
 -         struct Byte
 -         {
 -             enum { v = (int) Bit<tableIndex * 8 + 0>::v | (int) Bit<tableIndex * 8 + 1>::v
 -                      | (int) Bit<tableIndex * 8 + 2>::v | (int) Bit<tableIndex * 8 + 3>::v
 -                      | (int) Bit<tableIndex * 8 + 4>::v | (int) Bit<tableIndex * 8 + 5>::v
 -                      | (int) Bit<tableIndex * 8 + 6>::v | (int) Bit<tableIndex * 8 + 7>::v };
 -         };
 - 
 -         static bool isLegal (uint32 c) noexcept
 -         {
 -             static const unsigned char legalChars[] = { Byte< 0>::v, Byte< 1>::v, Byte< 2>::v, Byte< 3>::v,
 -                                                         Byte< 4>::v, Byte< 5>::v, Byte< 6>::v, Byte< 7>::v,
 -                                                         Byte< 8>::v, Byte< 9>::v, Byte<10>::v, Byte<11>::v,
 -                                                         Byte<12>::v, Byte<13>::v, Byte<14>::v, Byte<15>::v };
 - 
 -             return c < sizeof (legalChars) * 8
 -                      && (legalChars[c >> 3] & (1 << (c & 7))) != 0;
 -         }
 -     }
 - 
 -     static void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, bool changeNewLines)
 -     {
 -         auto t = text.getCharPointer();
 - 
 -         for (;;)
 -         {
 -             auto character = (uint32) t.getAndAdvance();
 - 
 -             if (character == 0)
 -                 break;
 - 
 -             if (LegalCharLookupTable::isLegal (character))
 -             {
 -                 outputStream << (char) character;
 -             }
 -             else
 -             {
 -                 switch (character)
 -                 {
 -                     case '&':   outputStream << "&"; break;
 -                     case '"':   outputStream << """; break;
 -                     case '>':   outputStream << ">"; break;
 -                     case '<':   outputStream << "<"; break;
 - 
 -                     case '\n':
 -                     case '\r':
 -                         if (! changeNewLines)
 -                         {
 -                             outputStream << (char) character;
 -                             break;
 -                         }
 -                         JUCE_FALLTHROUGH
 -                     default:
 -                         outputStream << "&#" << ((int) character) << ';';
 -                         break;
 -                 }
 -             }
 -         }
 -     }
 - 
 -     static void writeSpaces (OutputStream& out, const size_t numSpaces)
 -     {
 -         out.writeRepeatedByte (' ', numSpaces);
 -     }
 - }
 - 
 - void XmlElement::writeElementAsText (OutputStream& outputStream,
 -                                      int indentationLevel,
 -                                      int lineWrapLength,
 -                                      const char* newLineChars) const
 - {
 -     if (indentationLevel >= 0)
 -         XmlOutputFunctions::writeSpaces (outputStream, (size_t) indentationLevel);
 - 
 -     if (! isTextElement())
 -     {
 -         outputStream.writeByte ('<');
 -         outputStream << tagName;
 - 
 -         {
 -             auto attIndent = (size_t) (indentationLevel + tagName.length() + 1);
 -             int lineLen = 0;
 - 
 -             for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
 -             {
 -                 if (lineLen > lineWrapLength && indentationLevel >= 0)
 -                 {
 -                     outputStream << newLineChars;
 -                     XmlOutputFunctions::writeSpaces (outputStream, attIndent);
 -                     lineLen = 0;
 -                 }
 - 
 -                 auto startPos = outputStream.getPosition();
 -                 outputStream.writeByte (' ');
 -                 outputStream << att->name;
 -                 outputStream.write ("=\"", 2);
 -                 XmlOutputFunctions::escapeIllegalXmlChars (outputStream, att->value, true);
 -                 outputStream.writeByte ('"');
 -                 lineLen += (int) (outputStream.getPosition() - startPos);
 -             }
 -         }
 - 
 -         if (auto* child = firstChildElement.get())
 -         {
 -             outputStream.writeByte ('>');
 -             bool lastWasTextNode = false;
 - 
 -             for (; child != nullptr; child = child->nextListItem)
 -             {
 -                 if (child->isTextElement())
 -                 {
 -                     XmlOutputFunctions::escapeIllegalXmlChars (outputStream, child->getText(), false);
 -                     lastWasTextNode = true;
 -                 }
 -                 else
 -                 {
 -                     if (indentationLevel >= 0 && ! lastWasTextNode)
 -                         outputStream << newLineChars;
 - 
 -                     child->writeElementAsText (outputStream,
 -                                                lastWasTextNode ? 0 : (indentationLevel + (indentationLevel >= 0 ? 2 : 0)), lineWrapLength,
 -                                                newLineChars);
 -                     lastWasTextNode = false;
 -                 }
 -             }
 - 
 -             if (indentationLevel >= 0 && ! lastWasTextNode)
 -             {
 -                 outputStream << newLineChars;
 -                 XmlOutputFunctions::writeSpaces (outputStream, (size_t) indentationLevel);
 -             }
 - 
 -             outputStream.write ("</", 2);
 -             outputStream << tagName;
 -             outputStream.writeByte ('>');
 -         }
 -         else
 -         {
 -             outputStream.write ("/>", 2);
 -         }
 -     }
 -     else
 -     {
 -         XmlOutputFunctions::escapeIllegalXmlChars (outputStream, getText(), false);
 -     }
 - }
 - 
 - XmlElement::TextFormat::TextFormat() {}
 - 
 - XmlElement::TextFormat XmlElement::TextFormat::singleLine() const
 - {
 -     auto f = *this;
 -     f.newLineChars = nullptr;
 -     return f;
 - }
 - 
 - XmlElement::TextFormat XmlElement::TextFormat::withoutHeader() const
 - {
 -     auto f = *this;
 -     f.addDefaultHeader = false;
 -     return f;
 - }
 - 
 - String XmlElement::toString (const TextFormat& options) const
 - {
 -     MemoryOutputStream mem (2048);
 -     writeTo (mem, options);
 -     return mem.toUTF8();
 - }
 - 
 - void XmlElement::writeTo (OutputStream& output, const TextFormat& options) const
 - {
 -     if (options.customHeader.isNotEmpty())
 -     {
 -         output << options.customHeader;
 - 
 -         if (options.newLineChars == nullptr)
 -             output.writeByte (' ');
 -         else
 -             output << options.newLineChars
 -                    << options.newLineChars;
 -     }
 -     else if (options.addDefaultHeader)
 -     {
 -         output << "<?xml version=\"1.0\" encoding=\"";
 - 
 -         if (options.customEncoding.isNotEmpty())
 -             output << options.customEncoding;
 -         else
 -             output << "UTF-8";
 - 
 -         output << "\"?>";
 - 
 -         if (options.newLineChars == nullptr)
 -             output.writeByte (' ');
 -         else
 -             output << options.newLineChars
 -                    << options.newLineChars;
 -     }
 - 
 -     if (options.dtd.isNotEmpty())
 -     {
 -         output << options.dtd;
 - 
 -         if (options.newLineChars == nullptr)
 -             output.writeByte (' ');
 -         else
 -             output << options.newLineChars;
 -     }
 - 
 -     writeElementAsText (output, options.newLineChars == nullptr ? -1 : 0,
 -                         options.lineWrapLength,
 -                         options.newLineChars);
 - 
 -     if (options.newLineChars != nullptr)
 -         output << options.newLineChars;
 - }
 - 
 - bool XmlElement::writeTo (const File& destinationFile, const TextFormat& options) const
 - {
 -     TemporaryFile tempFile (destinationFile);
 - 
 -     {
 -         FileOutputStream out (tempFile.getFile());
 - 
 -         if (! out.openedOk())
 -             return false;
 - 
 -         writeTo (out, options);
 -         out.flush(); // (called explicitly to force an fsync on posix)
 - 
 -         if (out.getStatus().failed())
 -             return false;
 -     }
 - 
 -     return tempFile.overwriteTargetFileWithTemporary();
 - }
 - 
 - String XmlElement::createDocument (StringRef dtdToUse, bool allOnOneLine, bool includeXmlHeader,
 -                                    StringRef encodingType, int lineWrapLength) const
 - {
 -     TextFormat options;
 -     options.dtd = dtdToUse;
 -     options.customEncoding = encodingType;
 -     options.addDefaultHeader = includeXmlHeader;
 -     options.lineWrapLength = lineWrapLength;
 - 
 -     if (allOnOneLine)
 -         options.newLineChars = nullptr;
 - 
 -     return toString (options);
 - }
 - 
 - void XmlElement::writeToStream (OutputStream& output, StringRef dtdToUse,
 -                                 bool allOnOneLine, bool includeXmlHeader,
 -                                 StringRef encodingType, int lineWrapLength) const
 - {
 -     TextFormat options;
 -     options.dtd = dtdToUse;
 -     options.customEncoding = encodingType;
 -     options.addDefaultHeader = includeXmlHeader;
 -     options.lineWrapLength = lineWrapLength;
 - 
 -     if (allOnOneLine)
 -         options.newLineChars = nullptr;
 - 
 -     writeTo (output, options);
 - }
 - 
 - bool XmlElement::writeToFile (const File& file, StringRef dtdToUse,
 -                               StringRef encodingType, int lineWrapLength) const
 - {
 -     TextFormat options;
 -     options.dtd = dtdToUse;
 -     options.customEncoding = encodingType;
 -     options.lineWrapLength = lineWrapLength;
 - 
 -     return writeTo (file, options);
 - }
 - 
 - //==============================================================================
 - bool XmlElement::hasTagName (StringRef possibleTagName) const noexcept
 - {
 -     const bool matches = tagName.equalsIgnoreCase (possibleTagName);
 - 
 -     // XML tags should be case-sensitive, so although this method allows a
 -     // case-insensitive match to pass, you should try to avoid this.
 -     jassert ((! matches) || tagName == possibleTagName);
 - 
 -     return matches;
 - }
 - 
 - String XmlElement::getNamespace() const
 - {
 -     return tagName.upToFirstOccurrenceOf (":", false, false);
 - }
 - 
 - String XmlElement::getTagNameWithoutNamespace() const
 - {
 -     return tagName.fromLastOccurrenceOf (":", false, false);
 - }
 - 
 - bool XmlElement::hasTagNameIgnoringNamespace (StringRef possibleTagName) const
 - {
 -     return hasTagName (possibleTagName) || getTagNameWithoutNamespace() == possibleTagName;
 - }
 - 
 - XmlElement* XmlElement::getNextElementWithTagName (StringRef requiredTagName) const
 - {
 -     auto* e = nextListItem.get();
 - 
 -     while (e != nullptr && ! e->hasTagName (requiredTagName))
 -         e = e->nextListItem;
 - 
 -     return e;
 - }
 - 
 - void XmlElement::setTagName (StringRef newTagName)
 - {
 -     jassert (isValidXmlName (newTagName));
 -     tagName = StringPool::getGlobalPool().getPooledString (newTagName);
 - }
 - 
 - //==============================================================================
 - int XmlElement::getNumAttributes() const noexcept
 - {
 -     return attributes.size();
 - }
 - 
 - static const String& getEmptyStringRef() noexcept
 - {
 -     static String empty;
 -     return empty;
 - }
 - 
 - const String& XmlElement::getAttributeName (const int index) const noexcept
 - {
 -     if (auto* att = attributes[index].get())
 -         return att->name.toString();
 - 
 -     return getEmptyStringRef();
 - }
 - 
 - const String& XmlElement::getAttributeValue (const int index) const noexcept
 - {
 -     if (auto* att = attributes[index].get())
 -         return att->value;
 - 
 -     return getEmptyStringRef();
 - }
 - 
 - XmlElement::XmlAttributeNode* XmlElement::getAttribute (StringRef attributeName) const noexcept
 - {
 -     for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
 -         if (att->name == attributeName)
 -             return att;
 - 
 -     return nullptr;
 - }
 - 
 - bool XmlElement::hasAttribute (StringRef attributeName) const noexcept
 - {
 -     return getAttribute (attributeName) != nullptr;
 - }
 - 
 - //==============================================================================
 - const String& XmlElement::getStringAttribute (StringRef attributeName) const noexcept
 - {
 -     if (auto* att = getAttribute (attributeName))
 -         return att->value;
 - 
 -     return getEmptyStringRef();
 - }
 - 
 - String XmlElement::getStringAttribute (StringRef attributeName, const String& defaultReturnValue) const
 - {
 -     if (auto* att = getAttribute (attributeName))
 -         return att->value;
 - 
 -     return defaultReturnValue;
 - }
 - 
 - int XmlElement::getIntAttribute (StringRef attributeName, const int defaultReturnValue) const
 - {
 -     if (auto* att = getAttribute (attributeName))
 -         return att->value.getIntValue();
 - 
 -     return defaultReturnValue;
 - }
 - 
 - double XmlElement::getDoubleAttribute (StringRef attributeName, const double defaultReturnValue) const
 - {
 -     if (auto* att = getAttribute (attributeName))
 -         return att->value.getDoubleValue();
 - 
 -     return defaultReturnValue;
 - }
 - 
 - bool XmlElement::getBoolAttribute (StringRef attributeName, const bool defaultReturnValue) const
 - {
 -     if (auto* att = getAttribute (attributeName))
 -     {
 -         auto firstChar = *(att->value.getCharPointer().findEndOfWhitespace());
 - 
 -         return firstChar == '1'
 -             || firstChar == 't'
 -             || firstChar == 'y'
 -             || firstChar == 'T'
 -             || firstChar == 'Y';
 -     }
 - 
 -     return defaultReturnValue;
 - }
 - 
 - bool XmlElement::compareAttribute (StringRef attributeName,
 -                                    StringRef stringToCompareAgainst,
 -                                    const bool ignoreCase) const noexcept
 - {
 -     if (auto* att = getAttribute (attributeName))
 -         return ignoreCase ? att->value.equalsIgnoreCase (stringToCompareAgainst)
 -                           : att->value == stringToCompareAgainst;
 - 
 -     return false;
 - }
 - 
 - //==============================================================================
 - void XmlElement::setAttribute (const Identifier& attributeName, const String& value)
 - {
 -     if (attributes == nullptr)
 -     {
 -         attributes = new XmlAttributeNode (attributeName, value);
 -     }
 -     else
 -     {
 -         for (auto* att = attributes.get(); ; att = att->nextListItem)
 -         {
 -             if (att->name == attributeName)
 -             {
 -                 att->value = value;
 -                 break;
 -             }
 - 
 -             if (att->nextListItem == nullptr)
 -             {
 -                 att->nextListItem = new XmlAttributeNode (attributeName, value);
 -                 break;
 -             }
 -         }
 -     }
 - }
 - 
 - void XmlElement::setAttribute (const Identifier& attributeName, const int number)
 - {
 -     setAttribute (attributeName, String (number));
 - }
 - 
 - void XmlElement::setAttribute (const Identifier& attributeName, const double number)
 - {
 -     setAttribute (attributeName, serialiseDouble (number));
 - }
 - 
 - void XmlElement::removeAttribute (const Identifier& attributeName) noexcept
 - {
 -     for (auto* att = &attributes; att->get() != nullptr; att = &(att->get()->nextListItem))
 -     {
 -         if (att->get()->name == attributeName)
 -         {
 -             delete att->removeNext();
 -             break;
 -         }
 -     }
 - }
 - 
 - void XmlElement::removeAllAttributes() noexcept
 - {
 -     attributes.deleteAll();
 - }
 - 
 - //==============================================================================
 - int XmlElement::getNumChildElements() const noexcept
 - {
 -     return firstChildElement.size();
 - }
 - 
 - XmlElement* XmlElement::getChildElement (const int index) const noexcept
 - {
 -     return firstChildElement[index].get();
 - }
 - 
 - XmlElement* XmlElement::getChildByName (StringRef childName) const noexcept
 - {
 -     jassert (! childName.isEmpty());
 - 
 -     for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
 -         if (child->hasTagName (childName))
 -             return child;
 - 
 -     return nullptr;
 - }
 - 
 - XmlElement* XmlElement::getChildByAttribute (StringRef attributeName, StringRef attributeValue) const noexcept
 - {
 -     jassert (! attributeName.isEmpty());
 - 
 -     for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
 -         if (child->compareAttribute (attributeName, attributeValue))
 -             return child;
 - 
 -     return nullptr;
 - }
 - 
 - void XmlElement::addChildElement (XmlElement* const newNode) noexcept
 - {
 -     if (newNode != nullptr)
 -     {
 -         // The element being added must not be a child of another node!
 -         jassert (newNode->nextListItem == nullptr);
 - 
 -         firstChildElement.append (newNode);
 -     }
 - }
 - 
 - void XmlElement::insertChildElement (XmlElement* const newNode, int indexToInsertAt) noexcept
 - {
 -     if (newNode != nullptr)
 -     {
 -         // The element being added must not be a child of another node!
 -         jassert (newNode->nextListItem == nullptr);
 - 
 -         firstChildElement.insertAtIndex (indexToInsertAt, newNode);
 -     }
 - }
 - 
 - void XmlElement::prependChildElement (XmlElement* newNode) noexcept
 - {
 -     if (newNode != nullptr)
 -     {
 -         // The element being added must not be a child of another node!
 -         jassert (newNode->nextListItem == nullptr);
 - 
 -         firstChildElement.insertNext (newNode);
 -     }
 - }
 - 
 - XmlElement* XmlElement::createNewChildElement (StringRef childTagName)
 - {
 -     auto newElement = new XmlElement (childTagName);
 -     addChildElement (newElement);
 -     return newElement;
 - }
 - 
 - bool XmlElement::replaceChildElement (XmlElement* const currentChildElement,
 -                                       XmlElement* const newNode) noexcept
 - {
 -     if (newNode != nullptr)
 -     {
 -         if (auto* p = firstChildElement.findPointerTo (currentChildElement))
 -         {
 -             if (currentChildElement != newNode)
 -                 delete p->replaceNext (newNode);
 - 
 -             return true;
 -         }
 -     }
 - 
 -     return false;
 - }
 - 
 - void XmlElement::removeChildElement (XmlElement* const childToRemove,
 -                                      const bool shouldDeleteTheChild) noexcept
 - {
 -     if (childToRemove != nullptr)
 -     {
 -         jassert (containsChildElement (childToRemove));
 - 
 -         firstChildElement.remove (childToRemove);
 - 
 -         if (shouldDeleteTheChild)
 -             delete childToRemove;
 -     }
 - }
 - 
 - bool XmlElement::isEquivalentTo (const XmlElement* const other,
 -                                  const bool ignoreOrderOfAttributes) const noexcept
 - {
 -     if (this != other)
 -     {
 -         if (other == nullptr || tagName != other->tagName)
 -             return false;
 - 
 -         if (ignoreOrderOfAttributes)
 -         {
 -             int totalAtts = 0;
 - 
 -             for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
 -             {
 -                 if (! other->compareAttribute (att->name, att->value))
 -                     return false;
 - 
 -                 ++totalAtts;
 -             }
 - 
 -             if (totalAtts != other->getNumAttributes())
 -                 return false;
 -         }
 -         else
 -         {
 -             auto* thisAtt = attributes.get();
 -             auto* otherAtt = other->attributes.get();
 - 
 -             for (;;)
 -             {
 -                 if (thisAtt == nullptr || otherAtt == nullptr)
 -                 {
 -                     if (thisAtt == otherAtt) // both nullptr, so it's a match
 -                         break;
 - 
 -                     return false;
 -                 }
 - 
 -                 if (thisAtt->name != otherAtt->name
 -                      || thisAtt->value != otherAtt->value)
 -                 {
 -                     return false;
 -                 }
 - 
 -                 thisAtt = thisAtt->nextListItem;
 -                 otherAtt = otherAtt->nextListItem;
 -             }
 -         }
 - 
 -         auto* thisChild = firstChildElement.get();
 -         auto* otherChild = other->firstChildElement.get();
 - 
 -         for (;;)
 -         {
 -             if (thisChild == nullptr || otherChild == nullptr)
 -             {
 -                 if (thisChild == otherChild) // both 0, so it's a match
 -                     break;
 - 
 -                 return false;
 -             }
 - 
 -             if (! thisChild->isEquivalentTo (otherChild, ignoreOrderOfAttributes))
 -                 return false;
 - 
 -             thisChild = thisChild->nextListItem;
 -             otherChild = otherChild->nextListItem;
 -         }
 -     }
 - 
 -     return true;
 - }
 - 
 - void XmlElement::deleteAllChildElements() noexcept
 - {
 -     firstChildElement.deleteAll();
 - }
 - 
 - void XmlElement::deleteAllChildElementsWithTagName (StringRef name) noexcept
 - {
 -     for (auto* child = firstChildElement.get(); child != nullptr;)
 -     {
 -         auto* nextChild = child->nextListItem.get();
 - 
 -         if (child->hasTagName (name))
 -             removeChildElement (child, true);
 - 
 -         child = nextChild;
 -     }
 - }
 - 
 - bool XmlElement::containsChildElement (const XmlElement* const possibleChild) const noexcept
 - {
 -     return firstChildElement.contains (possibleChild);
 - }
 - 
 - XmlElement* XmlElement::findParentElementOf (const XmlElement* const elementToLookFor) noexcept
 - {
 -     if (this == elementToLookFor || elementToLookFor == nullptr)
 -         return nullptr;
 - 
 -     for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
 -     {
 -         if (elementToLookFor == child)
 -             return this;
 - 
 -         if (auto* found = child->findParentElementOf (elementToLookFor))
 -             return found;
 -     }
 - 
 -     return nullptr;
 - }
 - 
 - void XmlElement::getChildElementsAsArray (XmlElement** elems) const noexcept
 - {
 -     firstChildElement.copyToArray (elems);
 - }
 - 
 - void XmlElement::reorderChildElements (XmlElement** elems, int num) noexcept
 - {
 -     auto* e = elems[0];
 -     firstChildElement = e;
 - 
 -     for (int i = 1; i < num; ++i)
 -     {
 -         e->nextListItem = elems[i];
 -         e = e->nextListItem;
 -     }
 - 
 -     e->nextListItem = nullptr;
 - }
 - 
 - //==============================================================================
 - bool XmlElement::isTextElement() const noexcept
 - {
 -     return tagName.isEmpty();
 - }
 - 
 - static const String juce_xmltextContentAttributeName ("text");
 - 
 - const String& XmlElement::getText() const noexcept
 - {
 -     jassert (isTextElement());  // you're trying to get the text from an element that
 -                                 // isn't actually a text element.. If this contains text sub-nodes, you
 -                                 // probably want to use getAllSubText instead.
 - 
 -     return getStringAttribute (juce_xmltextContentAttributeName);
 - }
 - 
 - void XmlElement::setText (const String& newText)
 - {
 -     if (isTextElement())
 -         setAttribute (juce_xmltextContentAttributeName, newText);
 -     else
 -         jassertfalse; // you can only change the text in a text element, not a normal one.
 - }
 - 
 - String XmlElement::getAllSubText() const
 - {
 -     if (isTextElement())
 -         return getText();
 - 
 -     if (getNumChildElements() == 1)
 -         return firstChildElement.get()->getAllSubText();
 - 
 -     MemoryOutputStream mem (1024);
 - 
 -     for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
 -         mem << child->getAllSubText();
 - 
 -     return mem.toUTF8();
 - }
 - 
 - String XmlElement::getChildElementAllSubText (StringRef childTagName, const String& defaultReturnValue) const
 - {
 -     if (auto* child = getChildByName (childTagName))
 -         return child->getAllSubText();
 - 
 -     return defaultReturnValue;
 - }
 - 
 - XmlElement* XmlElement::createTextElement (const String& text)
 - {
 -     auto e = new XmlElement ((int) 0);
 -     e->setAttribute (juce_xmltextContentAttributeName, text);
 -     return e;
 - }
 - 
 - bool XmlElement::isValidXmlName (StringRef text) noexcept
 - {
 -     if (text.isEmpty() || ! isValidXmlNameStartCharacter (text.text.getAndAdvance()))
 -         return false;
 - 
 -     for (;;)
 -     {
 -         if (text.isEmpty())
 -             return true;
 - 
 -         if (! isValidXmlNameBodyCharacter (text.text.getAndAdvance()))
 -             return false;
 -     }
 - }
 - 
 - void XmlElement::addTextElement (const String& text)
 - {
 -     addChildElement (createTextElement (text));
 - }
 - 
 - void XmlElement::deleteAllTextElements() noexcept
 - {
 -     for (auto* child = firstChildElement.get(); child != nullptr;)
 -     {
 -         auto* next = child->nextListItem.get();
 - 
 -         if (child->isTextElement())
 -             removeChildElement (child, true);
 - 
 -         child = next;
 -     }
 - }
 - 
 - //==============================================================================
 - //==============================================================================
 - #if JUCE_UNIT_TESTS
 - 
 - class XmlElementTests final : public UnitTest
 - {
 - public:
 -     XmlElementTests()
 -         : UnitTest ("XmlElement", UnitTestCategories::xml)
 -     {}
 - 
 -     void runTest() override
 -     {
 -         {
 -             beginTest ("Float formatting");
 - 
 -             auto element = std::make_unique<XmlElement> ("test");
 -             Identifier number ("number");
 - 
 -             std::map<double, String> tests;
 -             tests[1] = "1.0";
 -             tests[1.1] = "1.1";
 -             tests[1.01] = "1.01";
 -             tests[0.76378] = "0.76378";
 -             tests[-10] = "-10.0";
 -             tests[10.01] = "10.01";
 -             tests[0.0123] = "0.0123";
 -             tests[-3.7e-27] = "-3.7e-27";
 -             tests[1e+40] = "1.0e40";
 -             tests[-12345678901234567.0] = "-1.234567890123457e16";
 -             tests[192000] = "192000.0";
 -             tests[1234567] = "1.234567e6";
 -             tests[0.00006] = "0.00006";
 -             tests[0.000006] = "6.0e-6";
 - 
 -             for (auto& test : tests)
 -             {
 -                 element->setAttribute (number, test.first);
 -                 expectEquals (element->getStringAttribute (number), test.second);
 -             }
 -         }
 -     }
 - };
 - 
 - static XmlElementTests xmlElementTests;
 - 
 - #endif
 - 
 - } // namespace juce
 
 
  |