LMMS
Loading...
Searching...
No Matches
juce_XmlElement.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26static bool isValidXmlNameStartCharacter (juce_wchar character) noexcept
27{
28 return character == ':'
29 || character == '_'
30 || (character >= 'a' && character <= 'z')
31 || (character >= 'A' && character <= 'Z')
32 || (character >= 0xc0 && character <= 0xd6)
33 || (character >= 0xd8 && character <= 0xf6)
34 || (character >= 0xf8 && character <= 0x2ff)
35 || (character >= 0x370 && character <= 0x37d)
36 || (character >= 0x37f && character <= 0x1fff)
37 || (character >= 0x200c && character <= 0x200d)
38 || (character >= 0x2070 && character <= 0x218f)
39 || (character >= 0x2c00 && character <= 0x2fef)
40 || (character >= 0x3001 && character <= 0xd7ff)
41 || (character >= 0xf900 && character <= 0xfdcf)
42 || (character >= 0xfdf0 && character <= 0xfffd)
43 || (character >= 0x10000 && character <= 0xeffff);
44}
45
46static bool isValidXmlNameBodyCharacter (juce_wchar character) noexcept
47{
48 return isValidXmlNameStartCharacter (character)
49 || character == '-'
50 || character == '.'
51 || character == 0xb7
52 || (character >= '0' && character <= '9')
53 || (character >= 0x300 && character <= 0x036f)
54 || (character >= 0x203f && character <= 0x2040);
55}
56
58 : name (other.name),
59 value (other.value)
60{
61}
62
68
69XmlElement::XmlAttributeNode::XmlAttributeNode (String::CharPointerType nameStart, String::CharPointerType nameEnd)
70 : name (nameStart, nameEnd)
71{
73}
74
75//==============================================================================
77 : tagName (StringPool::getGlobalPool().getPooledString (tag))
78{
80}
81
82XmlElement::XmlElement (const char* tag)
83 : tagName (StringPool::getGlobalPool().getPooledString (tag))
84{
86}
87
89 : tagName (StringPool::getGlobalPool().getPooledString (tag))
90{
92}
93
99
100XmlElement::XmlElement (String::CharPointerType tagNameStart, String::CharPointerType tagNameEnd)
101 : tagName (StringPool::getGlobalPool().getPooledString (tagNameStart, tagNameEnd))
102{
104}
105
106XmlElement::XmlElement (int /*dummy*/) noexcept
107{
108}
109
111 : tagName (other.tagName)
112{
114}
115
117{
118 if (this != &other)
119 {
122 tagName = other.tagName;
124 }
125
126 return *this;
127}
128
130 : nextListItem (std::move (other.nextListItem)),
131 firstChildElement (std::move (other.firstChildElement)),
132 attributes (std::move (other.attributes)),
133 tagName (std::move (other.tagName))
134{
135}
136
138{
139 jassert (this != &other); // hopefully the compiler should make this situation impossible!
140
143
144 nextListItem = std::move (other.nextListItem);
145 firstChildElement = std::move (other.firstChildElement);
146 attributes = std::move (other.attributes);
147 tagName = std::move (other.tagName);
148
149 return *this;
150}
151
153{
154 jassert (firstChildElement.get() == nullptr);
155 firstChildElement.addCopyOfList (other.firstChildElement);
156
157 jassert (attributes.get() == nullptr);
158 attributes.addCopyOfList (other.attributes);
159}
160
162{
163 firstChildElement.deleteAll();
164 attributes.deleteAll();
165}
166
167//==============================================================================
169{
171 {
172 template <int c>
173 struct Bit
174 {
175 enum { v = ((c >= 'a' && c <= 'z')
176 || (c >= 'A' && c <= 'Z')
177 || (c >= '0' && c <= '9')
178 || c == ' ' || c == '.' || c == ',' || c == ';'
179 || c == ':' || c == '-' || c == '(' || c == ')'
180 || c == '_' || c == '+' || c == '=' || c == '?'
181 || c == '!' || c == '$' || c == '#' || c == '@'
182 || c == '[' || c == ']' || c == '/' || c == '|'
183 || c == '*' || c == '%' || c == '~' || c == '{'
184 || c == '}' || c == '\'' || c == '\\')
185 ? (1 << (c & 7)) : 0 };
186 };
187
188 template <int tableIndex>
196
197 static bool isLegal (uint32 c) noexcept
198 {
199 static const unsigned char legalChars[] = { Byte< 0>::v, Byte< 1>::v, Byte< 2>::v, Byte< 3>::v,
203
204 return c < sizeof (legalChars) * 8
205 && (legalChars[c >> 3] & (1 << (c & 7))) != 0;
206 }
207 }
208
209 static void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, bool changeNewLines)
210 {
211 auto t = text.getCharPointer();
212
213 for (;;)
214 {
215 auto character = (uint32) t.getAndAdvance();
216
217 if (character == 0)
218 break;
219
220 if (LegalCharLookupTable::isLegal (character))
221 {
222 outputStream << (char) character;
223 }
224 else
225 {
226 switch (character)
227 {
228 case '&': outputStream << "&amp;"; break;
229 case '"': outputStream << "&quot;"; break;
230 case '>': outputStream << "&gt;"; break;
231 case '<': outputStream << "&lt;"; break;
232
233 case '\n':
234 case '\r':
235 if (! changeNewLines)
236 {
237 outputStream << (char) character;
238 break;
239 }
241 default:
242 outputStream << "&#" << ((int) character) << ';';
243 break;
244 }
245 }
246 }
247 }
248
249 static void writeSpaces (OutputStream& out, const size_t numSpaces)
250 {
251 out.writeRepeatedByte (' ', numSpaces);
252 }
253}
254
256 int indentationLevel,
257 int lineWrapLength,
258 const char* newLineChars) const
259{
260 if (indentationLevel >= 0)
261 XmlOutputFunctions::writeSpaces (outputStream, (size_t) indentationLevel);
262
263 if (! isTextElement())
264 {
265 outputStream.writeByte ('<');
266 outputStream << tagName;
267
268 {
269 auto attIndent = (size_t) (indentationLevel + tagName.length() + 1);
270 int lineLen = 0;
271
272 for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
273 {
274 if (lineLen > lineWrapLength && indentationLevel >= 0)
275 {
276 outputStream << newLineChars;
277 XmlOutputFunctions::writeSpaces (outputStream, attIndent);
278 lineLen = 0;
279 }
280
281 auto startPos = outputStream.getPosition();
282 outputStream.writeByte (' ');
283 outputStream << att->name;
284 outputStream.write ("=\"", 2);
285 XmlOutputFunctions::escapeIllegalXmlChars (outputStream, att->value, true);
286 outputStream.writeByte ('"');
287 lineLen += (int) (outputStream.getPosition() - startPos);
288 }
289 }
290
291 if (auto* child = firstChildElement.get())
292 {
293 outputStream.writeByte ('>');
294 bool lastWasTextNode = false;
295
296 for (; child != nullptr; child = child->nextListItem)
297 {
298 if (child->isTextElement())
299 {
300 XmlOutputFunctions::escapeIllegalXmlChars (outputStream, child->getText(), false);
301 lastWasTextNode = true;
302 }
303 else
304 {
305 if (indentationLevel >= 0 && ! lastWasTextNode)
306 outputStream << newLineChars;
307
308 child->writeElementAsText (outputStream,
309 lastWasTextNode ? 0 : (indentationLevel + (indentationLevel >= 0 ? 2 : 0)), lineWrapLength,
310 newLineChars);
311 lastWasTextNode = false;
312 }
313 }
314
315 if (indentationLevel >= 0 && ! lastWasTextNode)
316 {
317 outputStream << newLineChars;
318 XmlOutputFunctions::writeSpaces (outputStream, (size_t) indentationLevel);
319 }
320
321 outputStream.write ("</", 2);
322 outputStream << tagName;
323 outputStream.writeByte ('>');
324 }
325 else
326 {
327 outputStream.write ("/>", 2);
328 }
329 }
330 else
331 {
332 XmlOutputFunctions::escapeIllegalXmlChars (outputStream, getText(), false);
333 }
334}
335
337
339{
340 auto f = *this;
341 f.newLineChars = nullptr;
342 return f;
343}
344
346{
347 auto f = *this;
348 f.addDefaultHeader = false;
349 return f;
350}
351
353{
354 MemoryOutputStream mem (2048);
355 writeTo (mem, options);
356 return mem.toUTF8();
357}
358
359void XmlElement::writeTo (OutputStream& output, const TextFormat& options) const
360{
361 if (options.customHeader.isNotEmpty())
362 {
363 output << options.customHeader;
364
365 if (options.newLineChars == nullptr)
366 output.writeByte (' ');
367 else
368 output << options.newLineChars
369 << options.newLineChars;
370 }
371 else if (options.addDefaultHeader)
372 {
373 output << "<?xml version=\"1.0\" encoding=\"";
374
375 if (options.customEncoding.isNotEmpty())
376 output << options.customEncoding;
377 else
378 output << "UTF-8";
379
380 output << "\"?>";
381
382 if (options.newLineChars == nullptr)
383 output.writeByte (' ');
384 else
385 output << options.newLineChars
386 << options.newLineChars;
387 }
388
389 if (options.dtd.isNotEmpty())
390 {
391 output << options.dtd;
392
393 if (options.newLineChars == nullptr)
394 output.writeByte (' ');
395 else
396 output << options.newLineChars;
397 }
398
399 writeElementAsText (output, options.newLineChars == nullptr ? -1 : 0,
400 options.lineWrapLength,
401 options.newLineChars);
402
403 if (options.newLineChars != nullptr)
404 output << options.newLineChars;
405}
406
407bool XmlElement::writeTo (const File& destinationFile, const TextFormat& options) const
408{
409 TemporaryFile tempFile (destinationFile);
410
411 {
412 FileOutputStream out (tempFile.getFile());
413
414 if (! out.openedOk())
415 return false;
416
417 writeTo (out, options);
418 out.flush(); // (called explicitly to force an fsync on posix)
419
420 if (out.getStatus().failed())
421 return false;
422 }
423
424 return tempFile.overwriteTargetFileWithTemporary();
425}
426
427String XmlElement::createDocument (StringRef dtdToUse, bool allOnOneLine, bool includeXmlHeader,
428 StringRef encodingType, int lineWrapLength) const
429{
430 TextFormat options;
431 options.dtd = dtdToUse;
432 options.customEncoding = encodingType;
433 options.addDefaultHeader = includeXmlHeader;
434 options.lineWrapLength = lineWrapLength;
435
436 if (allOnOneLine)
437 options.newLineChars = nullptr;
438
439 return toString (options);
440}
441
443 bool allOnOneLine, bool includeXmlHeader,
444 StringRef encodingType, int lineWrapLength) const
445{
446 TextFormat options;
447 options.dtd = dtdToUse;
448 options.customEncoding = encodingType;
449 options.addDefaultHeader = includeXmlHeader;
450 options.lineWrapLength = lineWrapLength;
451
452 if (allOnOneLine)
453 options.newLineChars = nullptr;
454
455 writeTo (output, options);
456}
457
459 StringRef encodingType, int lineWrapLength) const
460{
461 TextFormat options;
462 options.dtd = dtdToUse;
463 options.customEncoding = encodingType;
464 options.lineWrapLength = lineWrapLength;
465
466 return writeTo (file, options);
467}
468
469//==============================================================================
470bool XmlElement::hasTagName (StringRef possibleTagName) const noexcept
471{
472 const bool matches = tagName.equalsIgnoreCase (possibleTagName);
473
474 // XML tags should be case-sensitive, so although this method allows a
475 // case-insensitive match to pass, you should try to avoid this.
476 jassert ((! matches) || tagName == possibleTagName);
477
478 return matches;
479}
480
482{
483 return tagName.upToFirstOccurrenceOf (":", false, false);
484}
485
487{
488 return tagName.fromLastOccurrenceOf (":", false, false);
489}
490
492{
493 return hasTagName (possibleTagName) || getTagNameWithoutNamespace() == possibleTagName;
494}
495
497{
498 auto* e = nextListItem.get();
499
500 while (e != nullptr && ! e->hasTagName (requiredTagName))
501 e = e->nextListItem;
502
503 return e;
504}
505
507{
508 jassert (isValidXmlName (newTagName));
509 tagName = StringPool::getGlobalPool().getPooledString (newTagName);
510}
511
512//==============================================================================
514{
515 return attributes.size();
516}
517
519{
520 static String empty;
521 return empty;
522}
523
524const String& XmlElement::getAttributeName (const int index) const noexcept
525{
526 if (auto* att = attributes[index].get())
527 return att->name.toString();
528
529 return getEmptyStringRef();
530}
531
532const String& XmlElement::getAttributeValue (const int index) const noexcept
533{
534 if (auto* att = attributes[index].get())
535 return att->value;
536
537 return getEmptyStringRef();
538}
539
541{
542 for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
543 if (att->name == attributeName)
544 return att;
545
546 return nullptr;
547}
548
549bool XmlElement::hasAttribute (StringRef attributeName) const noexcept
550{
551 return getAttribute (attributeName) != nullptr;
552}
553
554//==============================================================================
555const String& XmlElement::getStringAttribute (StringRef attributeName) const noexcept
556{
557 if (auto* att = getAttribute (attributeName))
558 return att->value;
559
560 return getEmptyStringRef();
561}
562
563String XmlElement::getStringAttribute (StringRef attributeName, const String& defaultReturnValue) const
564{
565 if (auto* att = getAttribute (attributeName))
566 return att->value;
567
568 return defaultReturnValue;
569}
570
571int XmlElement::getIntAttribute (StringRef attributeName, const int defaultReturnValue) const
572{
573 if (auto* att = getAttribute (attributeName))
574 return att->value.getIntValue();
575
576 return defaultReturnValue;
577}
578
579double XmlElement::getDoubleAttribute (StringRef attributeName, const double defaultReturnValue) const
580{
581 if (auto* att = getAttribute (attributeName))
582 return att->value.getDoubleValue();
583
584 return defaultReturnValue;
585}
586
587bool XmlElement::getBoolAttribute (StringRef attributeName, const bool defaultReturnValue) const
588{
589 if (auto* att = getAttribute (attributeName))
590 {
591 auto firstChar = *(att->value.getCharPointer().findEndOfWhitespace());
592
593 return firstChar == '1'
594 || firstChar == 't'
595 || firstChar == 'y'
596 || firstChar == 'T'
597 || firstChar == 'Y';
598 }
599
600 return defaultReturnValue;
601}
602
604 StringRef stringToCompareAgainst,
605 const bool ignoreCase) const noexcept
606{
607 if (auto* att = getAttribute (attributeName))
608 return ignoreCase ? att->value.equalsIgnoreCase (stringToCompareAgainst)
609 : att->value == stringToCompareAgainst;
610
611 return false;
612}
613
614//==============================================================================
615void XmlElement::setAttribute (const Identifier& attributeName, const String& value)
616{
617 if (attributes == nullptr)
618 {
619 attributes = new XmlAttributeNode (attributeName, value);
620 }
621 else
622 {
623 for (auto* att = attributes.get(); ; att = att->nextListItem)
624 {
625 if (att->name == attributeName)
626 {
627 att->value = value;
628 break;
629 }
630
631 if (att->nextListItem == nullptr)
632 {
633 att->nextListItem = new XmlAttributeNode (attributeName, value);
634 break;
635 }
636 }
637 }
638}
639
640void XmlElement::setAttribute (const Identifier& attributeName, const int number)
641{
642 setAttribute (attributeName, String (number));
643}
644
645void XmlElement::setAttribute (const Identifier& attributeName, const double number)
646{
647 setAttribute (attributeName, serialiseDouble (number));
648}
649
650void XmlElement::removeAttribute (const Identifier& attributeName) noexcept
651{
652 for (auto* att = &attributes; att->get() != nullptr; att = &(att->get()->nextListItem))
653 {
654 if (att->get()->name == attributeName)
655 {
656 delete att->removeNext();
657 break;
658 }
659 }
660}
661
663{
664 attributes.deleteAll();
665}
666
667//==============================================================================
672
673XmlElement* XmlElement::getChildElement (const int index) const noexcept
674{
675 return firstChildElement[index].get();
676}
677
679{
680 jassert (! childName.isEmpty());
681
682 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
683 if (child->hasTagName (childName))
684 return child;
685
686 return nullptr;
687}
688
689XmlElement* XmlElement::getChildByAttribute (StringRef attributeName, StringRef attributeValue) const noexcept
690{
691 jassert (! attributeName.isEmpty());
692
693 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
694 if (child->compareAttribute (attributeName, attributeValue))
695 return child;
696
697 return nullptr;
698}
699
700void XmlElement::addChildElement (XmlElement* const newNode) noexcept
701{
702 if (newNode != nullptr)
703 {
704 // The element being added must not be a child of another node!
705 jassert (newNode->nextListItem == nullptr);
706
707 firstChildElement.append (newNode);
708 }
709}
710
711void XmlElement::insertChildElement (XmlElement* const newNode, int indexToInsertAt) noexcept
712{
713 if (newNode != nullptr)
714 {
715 // The element being added must not be a child of another node!
716 jassert (newNode->nextListItem == nullptr);
717
718 firstChildElement.insertAtIndex (indexToInsertAt, newNode);
719 }
720}
721
723{
724 if (newNode != nullptr)
725 {
726 // The element being added must not be a child of another node!
727 jassert (newNode->nextListItem == nullptr);
728
729 firstChildElement.insertNext (newNode);
730 }
731}
732
734{
735 auto newElement = new XmlElement (childTagName);
736 addChildElement (newElement);
737 return newElement;
738}
739
740bool XmlElement::replaceChildElement (XmlElement* const currentChildElement,
741 XmlElement* const newNode) noexcept
742{
743 if (newNode != nullptr)
744 {
745 if (auto* p = firstChildElement.findPointerTo (currentChildElement))
746 {
747 if (currentChildElement != newNode)
748 delete p->replaceNext (newNode);
749
750 return true;
751 }
752 }
753
754 return false;
755}
756
758 const bool shouldDeleteTheChild) noexcept
759{
760 if (childToRemove != nullptr)
761 {
762 jassert (containsChildElement (childToRemove));
763
764 firstChildElement.remove (childToRemove);
765
766 if (shouldDeleteTheChild)
767 delete childToRemove;
768 }
769}
770
771bool XmlElement::isEquivalentTo (const XmlElement* const other,
772 const bool ignoreOrderOfAttributes) const noexcept
773{
774 if (this != other)
775 {
776 if (other == nullptr || tagName != other->tagName)
777 return false;
778
779 if (ignoreOrderOfAttributes)
780 {
781 int totalAtts = 0;
782
783 for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
784 {
785 if (! other->compareAttribute (att->name, att->value))
786 return false;
787
788 ++totalAtts;
789 }
790
791 if (totalAtts != other->getNumAttributes())
792 return false;
793 }
794 else
795 {
796 auto* thisAtt = attributes.get();
797 auto* otherAtt = other->attributes.get();
798
799 for (;;)
800 {
801 if (thisAtt == nullptr || otherAtt == nullptr)
802 {
803 if (thisAtt == otherAtt) // both nullptr, so it's a match
804 break;
805
806 return false;
807 }
808
809 if (thisAtt->name != otherAtt->name
810 || thisAtt->value != otherAtt->value)
811 {
812 return false;
813 }
814
815 thisAtt = thisAtt->nextListItem;
816 otherAtt = otherAtt->nextListItem;
817 }
818 }
819
820 auto* thisChild = firstChildElement.get();
821 auto* otherChild = other->firstChildElement.get();
822
823 for (;;)
824 {
825 if (thisChild == nullptr || otherChild == nullptr)
826 {
827 if (thisChild == otherChild) // both 0, so it's a match
828 break;
829
830 return false;
831 }
832
833 if (! thisChild->isEquivalentTo (otherChild, ignoreOrderOfAttributes))
834 return false;
835
836 thisChild = thisChild->nextListItem;
837 otherChild = otherChild->nextListItem;
838 }
839 }
840
841 return true;
842}
843
848
850{
851 for (auto* child = firstChildElement.get(); child != nullptr;)
852 {
853 auto* nextChild = child->nextListItem.get();
854
855 if (child->hasTagName (name))
856 removeChildElement (child, true);
857
858 child = nextChild;
859 }
860}
861
862bool XmlElement::containsChildElement (const XmlElement* const possibleChild) const noexcept
863{
864 return firstChildElement.contains (possibleChild);
865}
866
867XmlElement* XmlElement::findParentElementOf (const XmlElement* const elementToLookFor) noexcept
868{
869 if (this == elementToLookFor || elementToLookFor == nullptr)
870 return nullptr;
871
872 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
873 {
874 if (elementToLookFor == child)
875 return this;
876
877 if (auto* found = child->findParentElementOf (elementToLookFor))
878 return found;
879 }
880
881 return nullptr;
882}
883
885{
886 firstChildElement.copyToArray (elems);
887}
888
889void XmlElement::reorderChildElements (XmlElement** elems, int num) noexcept
890{
891 auto* e = elems[0];
893
894 for (int i = 1; i < num; ++i)
895 {
896 e->nextListItem = elems[i];
897 e = e->nextListItem;
898 }
899
900 e->nextListItem = nullptr;
901}
902
903//==============================================================================
905{
906 return tagName.isEmpty();
907}
908
910
912{
913 jassert (isTextElement()); // you're trying to get the text from an element that
914 // isn't actually a text element.. If this contains text sub-nodes, you
915 // probably want to use getAllSubText instead.
916
918}
919
920void XmlElement::setText (const String& newText)
921{
922 if (isTextElement())
924 else
925 jassertfalse; // you can only change the text in a text element, not a normal one.
926}
927
929{
930 if (isTextElement())
931 return getText();
932
933 if (getNumChildElements() == 1)
934 return firstChildElement.get()->getAllSubText();
935
936 MemoryOutputStream mem (1024);
937
938 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
939 mem << child->getAllSubText();
940
941 return mem.toUTF8();
942}
943
944String XmlElement::getChildElementAllSubText (StringRef childTagName, const String& defaultReturnValue) const
945{
946 if (auto* child = getChildByName (childTagName))
947 return child->getAllSubText();
948
949 return defaultReturnValue;
950}
951
953{
954 auto e = new XmlElement ((int) 0);
955 e->setAttribute (juce_xmltextContentAttributeName, text);
956 return e;
957}
958
960{
961 if (text.isEmpty() || ! isValidXmlNameStartCharacter (text.text.getAndAdvance()))
962 return false;
963
964 for (;;)
965 {
966 if (text.isEmpty())
967 return true;
968
969 if (! isValidXmlNameBodyCharacter (text.text.getAndAdvance()))
970 return false;
971 }
972}
973
978
980{
981 for (auto* child = firstChildElement.get(); child != nullptr;)
982 {
983 auto* next = child->nextListItem.get();
984
985 if (child->isTextElement())
986 removeChildElement (child, true);
987
988 child = next;
989 }
990}
991
992//==============================================================================
993//==============================================================================
994#if JUCE_UNIT_TESTS
995
996class XmlElementTests : public UnitTest
997{
998public:
999 XmlElementTests()
1000 : UnitTest ("XmlElement", UnitTestCategories::xml)
1001 {}
1002
1003 void runTest() override
1004 {
1005 {
1006 beginTest ("Float formatting");
1007
1008 auto element = std::make_unique<XmlElement> ("test");
1009 Identifier number ("number");
1010
1011 std::map<double, String> tests;
1012 tests[1] = "1.0";
1013 tests[1.1] = "1.1";
1014 tests[1.01] = "1.01";
1015 tests[0.76378] = "0.76378";
1016 tests[-10] = "-10.0";
1017 tests[10.01] = "10.01";
1018 tests[0.0123] = "0.0123";
1019 tests[-3.7e-27] = "-3.7e-27";
1020 tests[1e+40] = "1.0e40";
1021 tests[-12345678901234567.0] = "-1.234567890123457e16";
1022 tests[192000] = "192000.0";
1023 tests[1234567] = "1.234567e6";
1024 tests[0.00006] = "0.00006";
1025 tests[0.000006] = "6.0e-6";
1026
1027 for (auto& test : tests)
1028 {
1029 element->setAttribute (number, test.first);
1030 expectEquals (element->getStringAttribute (number), test.second);
1031 }
1032 }
1033 }
1034};
1035
1036static XmlElementTests xmlElementTests;
1037
1038#endif
1039
1040} // namespace juce
#define noexcept
Definition DistrhoDefines.h:72
const std::string & getAttributeName(int attributeIndex) const noexcept
Definition XmlElement.cpp:457
void copyChildrenAndAttributesFrom(const XmlElement &)
Definition XmlElement.cpp:136
XmlElement * getChildByName(StringRef tagNameToLookFor) const noexcept
Definition XmlElement.cpp:613
XmlElement * getChildElement(int index) const noexcept
Definition XmlElement.cpp:608
bool hasTagName(StringRef possibleTagName) const noexcept
Definition XmlElement.cpp:403
bool compareAttribute(StringRef attributeName, StringRef stringToCompareAgainst, bool ignoreCase=false) const noexcept
Definition XmlElement.cpp:536
XmlElement * createNewChildElement(StringRef tagName)
Definition XmlElement.cpp:668
XmlElement * getChildByAttribute(StringRef attributeName, StringRef attributeValue) const noexcept
Definition XmlElement.cpp:624
bool hasAttribute(StringRef attributeName) const noexcept
Definition XmlElement.cpp:482
void addChildElement(XmlElement *newChildElement) noexcept
Definition XmlElement.cpp:635
String createDocument(StringRef dtdToUse, bool allOnOneLine=false, bool includeXmlHeader=true, StringRef encodingType="UTF-8", int lineWrapLength=60) const
Definition XmlElement.cpp:327
void deleteAllTextElements() noexcept
Definition XmlElement.cpp:909
void setText(const String &newText)
Definition XmlElement.cpp:852
bool replaceChildElement(XmlElement *currentChildElement, XmlElement *newChildNode) noexcept
Definition XmlElement.cpp:675
void prependChildElement(XmlElement *newChildElement) noexcept
Definition XmlElement.cpp:657
void deleteAllChildElementsWithTagName(StringRef tagName) noexcept
Definition XmlElement.cpp:782
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
Definition XmlElement.cpp:504
void writeElementAsText(OutputStream &, int indentationLevel, int lineWrapLength) const
Definition XmlElement.cpp:243
XmlElement(const String &tagName)
Definition XmlElement.cpp:83
double getDoubleAttribute(StringRef attributeName, double defaultReturnValue=0.0) const
Definition XmlElement.cpp:512
XmlElement * getNextElementWithTagName(StringRef requiredTagName) const
Definition XmlElement.cpp:429
int getNumChildElements() const noexcept
Definition XmlElement.cpp:603
const String & getStringAttribute(StringRef attributeName) const noexcept
Definition XmlElement.cpp:488
String getAllSubText() const
Definition XmlElement.cpp:858
void removeChildElement(XmlElement *childToRemove, bool shouldDeleteTheChild) noexcept
Definition XmlElement.cpp:692
bool isTextElement() const noexcept
Definition XmlElement.cpp:836
bool isEquivalentTo(const XmlElement *other, bool ignoreOrderOfAttributes) const noexcept
Definition XmlElement.cpp:704
void getChildElementsAsArray(XmlElement **) const noexcept
Definition XmlElement.cpp:817
String getChildElementAllSubText(StringRef childTagName, const String &defaultReturnValue) const
Definition XmlElement.cpp:874
void removeAttribute(const Identifier &attributeName) noexcept
Definition XmlElement.cpp:583
bool hasTagNameIgnoringNamespace(StringRef possibleTagName) const
Definition XmlElement.cpp:424
void reorderChildElements(XmlElement **, int) noexcept
Definition XmlElement.cpp:822
void insertChildElement(XmlElement *newChildElement, int indexToInsertAt) noexcept
Definition XmlElement.cpp:646
XmlAttributeNode * getAttribute(StringRef) const noexcept
Definition XmlElement.cpp:473
const String & getAttributeValue(int attributeIndex) const noexcept
Definition XmlElement.cpp:465
XmlElement & operator=(const XmlElement &)
Definition XmlElement.cpp:123
int getNumAttributes() const noexcept
Definition XmlElement.cpp:440
static XmlElement * createTextElement(const String &text)
Definition XmlElement.cpp:882
void addTextElement(const String &text)
Definition XmlElement.cpp:904
String getTagNameWithoutNamespace() const
Definition XmlElement.cpp:419
void writeToStream(OutputStream &output, StringRef dtdToUse, bool allOnOneLine=false, bool includeXmlHeader=true, StringRef encodingType="UTF-8", int lineWrapLength=60) const
Definition XmlElement.cpp:339
const String & getText() const noexcept
Definition XmlElement.cpp:843
static bool isValidXmlName(StringRef possibleName) noexcept
Definition XmlElement.cpp:889
~XmlElement() noexcept
Definition XmlElement.cpp:145
void setAttribute(const Identifier &attributeName, const String &newValue)
Definition XmlElement.cpp:548
bool getBoolAttribute(StringRef attributeName, bool defaultReturnValue=false) const
Definition XmlElement.cpp:520
void removeAllAttributes() noexcept
Definition XmlElement.cpp:597
String getNamespace() const
Definition XmlElement.cpp:414
bool containsChildElement(const XmlElement *possibleChild) const noexcept
Definition XmlElement.cpp:795
XmlElement * findParentElementOf(const XmlElement *childToSearchFor) noexcept
Definition XmlElement.cpp:800
void deleteAllChildElements() noexcept
Definition XmlElement.cpp:777
Definition juce_File.h:45
Definition juce_FileOutputStream.h:35
Definition juce_Identifier.h:39
Definition juce_MemoryOutputStream.h:36
String toUTF8() const
Definition juce_MemoryOutputStream.cpp:189
Definition juce_OutputStream.h:38
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
virtual int64 getPosition()=0
virtual bool writeByte(char byte)
Definition juce_OutputStream.cpp:83
Definition juce_String.h:53
int getIntValue() const noexcept
Definition juce_String.cpp:1871
bool isNotEmpty() const noexcept
Definition juce_String.h:316
Definition juce_StringPool.h:40
static StringPool & getGlobalPool() noexcept
Definition juce_StringPool.cpp:158
Definition juce_StringRef.h:62
Definition juce_TemporaryFile.h:65
bool overwriteTargetFileWithTemporary() const
Definition juce_TemporaryFile.cpp:93
const File & getFile() const noexcept
Definition juce_TemporaryFile.h:126
Definition juce_UnitTest.h:70
void setTagName(StringRef newTagName)
Definition juce_XmlElement.cpp:506
int getNumChildElements() const noexcept
Definition juce_XmlElement.cpp:668
XmlElement(const String &tagName)
Definition juce_XmlElement.cpp:76
XmlElement * getChildByName(StringRef tagNameToLookFor) const noexcept
Definition juce_XmlElement.cpp:678
bool isTextElement() const noexcept
Definition juce_XmlElement.cpp:904
String toString(const TextFormat &format={}) const
Definition juce_XmlElement.cpp:352
void addChildElement(XmlElement *newChildElement) noexcept
Definition juce_XmlElement.cpp:700
LinkedListPointer< XmlElement > firstChildElement
Definition juce_XmlElement.h:782
LinkedListPointer< XmlAttributeNode > attributes
Definition juce_XmlElement.h:783
String getTagNameWithoutNamespace() const
Definition juce_XmlElement.cpp:486
void writeElementAsText(OutputStream &, int, int, const char *) const
Definition juce_XmlElement.cpp:255
const String & getText() const noexcept
Definition juce_XmlElement.cpp:911
void copyChildrenAndAttributesFrom(const XmlElement &)
Definition juce_XmlElement.cpp:152
String tagName
Definition juce_XmlElement.h:784
void removeAllAttributes() noexcept
Definition juce_XmlElement.cpp:662
static XmlElement * createTextElement(const String &text)
Definition juce_XmlElement.cpp:952
LinkedListPointer< XmlElement > nextListItem
Definition juce_XmlElement.h:782
bool containsChildElement(const XmlElement *possibleChild) const noexcept
Definition juce_XmlElement.cpp:862
void writeTo(OutputStream &output, const TextFormat &format={}) const
Definition juce_XmlElement.cpp:359
bool writeToFile(const File &destinationFile, StringRef dtdToUse, StringRef encodingType="UTF-8", int lineWrapLength=60) const
Definition juce_XmlElement.cpp:458
void deleteAllChildElements() noexcept
Definition juce_XmlElement.cpp:844
bool hasTagName(StringRef possibleTagName) const noexcept
Definition juce_XmlElement.cpp:470
XmlAttributeNode * getAttribute(StringRef) const noexcept
Definition juce_XmlElement.cpp:540
void removeChildElement(XmlElement *childToRemove, bool shouldDeleteTheChild) noexcept
Definition juce_XmlElement.cpp:757
static bool isValidXmlName(StringRef possibleName) noexcept
Definition juce_XmlElement.cpp:959
const String & getStringAttribute(StringRef attributeName) const noexcept
Definition juce_XmlElement.cpp:555
void setAttribute(const Identifier &attributeName, const String &newValue)
Definition juce_XmlElement.cpp:615
* e
Definition inflate.c:1404
struct huft * t
Definition inflate.c:943
unsigned v[N_MAX]
Definition inflate.c:1584
register unsigned i
Definition inflate.c:1575
unsigned f
Definition inflate.c:1572
static PuglViewHint int value
Definition pugl.h:1708
static const char * name
Definition pugl.h:1582
#define jassert(expression)
#define jassertfalse
#define JUCE_FALLTHROUGH
static struct TestCase tests[]
Definition lilv_test.c:2218
float out
Definition lilv_test.c:1461
Definition juce_UnitTestCategories.h:27
Definition juce_XmlElement.cpp:169
static void escapeIllegalXmlChars(OutputStream &outputStream, const String &text, bool changeNewLines)
Definition juce_XmlElement.cpp:209
static void writeSpaces(OutputStream &out, const size_t numSpaces)
Definition juce_XmlElement.cpp:249
Definition carla_juce.cpp:31
unsigned int uint32
Definition juce_MathsFunctions.h:45
static const String & getEmptyStringRef() noexcept
Definition juce_XmlElement.cpp:518
static String serialiseDouble(double input)
Definition juce_String.cpp:2260
wchar_t juce_wchar
Definition juce_CharacterFunctions.h:42
static const String juce_xmltextContentAttributeName("text")
static bool isValidXmlNameStartCharacter(juce_wchar character) noexcept
Definition juce_XmlElement.cpp:26
static bool isValidXmlNameBodyCharacter(juce_wchar character) noexcept
Definition juce_XmlElement.cpp:46
static int test(SerdEnv *env, bool top_level, bool pretty_numbers)
Definition sratom_test.c:79
XmlAttributeNode(const XmlAttributeNode &) noexcept
Definition XmlElement.cpp:64
Definition juce_XmlElement.h:136
String customEncoding
Definition juce_XmlElement.h:142
JUCE_NODISCARD TextFormat withoutHeader() const
Definition juce_XmlElement.cpp:345
bool addDefaultHeader
Definition juce_XmlElement.h:143
String dtd
Definition juce_XmlElement.h:140
const char * newLineChars
Definition juce_XmlElement.h:145
String customHeader
Definition juce_XmlElement.h:141
JUCE_NODISCARD TextFormat singleLine() const
Definition juce_XmlElement.cpp:338
int lineWrapLength
Definition juce_XmlElement.h:144
TextFormat()
Definition juce_XmlElement.cpp:336
Definition juce_XmlElement.h:763
Identifier name
Definition juce_XmlElement.h:769
XmlAttributeNode(const XmlAttributeNode &) noexcept
Definition juce_XmlElement.cpp:57
const char * text
Definition swell-functions.h:167
int n
Definition crypt.c:458
uch * p
Definition crypt.c:594
return c
Definition crypt.c:175
typedef int(UZ_EXP MsgFn)()
struct zdirent * file
Definition win32.c:1500
#define const
Definition zconf.h:137