OpenShot Library | libopenshot-audio 0.2.0
juce_XmlDocument.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
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
26XmlDocument::XmlDocument (const String& text) : originalText (text) {}
27XmlDocument::XmlDocument (const File& file) : inputSource (new FileInputSource (file)) {}
28
30
32{
33 XmlDocument doc (file);
34 return doc.getDocumentElement();
35}
36
38{
39 XmlDocument doc (xmlData);
40 return doc.getDocumentElement();
41}
42
43std::unique_ptr<XmlElement> parseXML (const String& textToParse)
44{
45 return std::unique_ptr<XmlElement> (XmlDocument::parse (textToParse));
46}
47
48std::unique_ptr<XmlElement> parseXML (const File& fileToParse)
49{
50 return std::unique_ptr<XmlElement> (XmlDocument::parse (fileToParse));
51}
52
53void XmlDocument::setInputSource (InputSource* newSource) noexcept
54{
55 inputSource.reset (newSource);
56}
57
58void XmlDocument::setEmptyTextElementsIgnored (bool shouldBeIgnored) noexcept
59{
60 ignoreEmptyTextElements = shouldBeIgnored;
61}
62
63namespace XmlIdentifierChars
64{
65 static bool isIdentifierCharSlow (juce_wchar c) noexcept
66 {
68 || c == '_' || c == '-' || c == ':' || c == '.';
69 }
70
71 static bool isIdentifierChar (juce_wchar c) noexcept
72 {
73 static const uint32 legalChars[] = { 0, 0x7ff6000, 0x87fffffe, 0x7fffffe, 0 };
74
75 return ((int) c < (int) numElementsInArray (legalChars) * 32) ? ((legalChars [c >> 5] & (1 << (c & 31))) != 0)
76 : isIdentifierCharSlow (c);
77 }
78
79 /*static void generateIdentifierCharConstants()
80 {
81 uint32 n[8] = { 0 };
82 for (int i = 0; i < 256; ++i)
83 if (isIdentifierCharSlow (i))
84 n[i >> 5] |= (1 << (i & 31));
85
86 String s;
87 for (int i = 0; i < 8; ++i)
88 s << "0x" << String::toHexString ((int) n[i]) << ", ";
89
90 DBG (s);
91 }*/
92
93 static String::CharPointerType findEndOfToken (String::CharPointerType p) noexcept
94 {
95 while (isIdentifierChar (*p))
96 ++p;
97
98 return p;
99 }
100}
101
102XmlElement* XmlDocument::getDocumentElement (const bool onlyReadOuterDocumentElement)
103{
104 if (originalText.isEmpty() && inputSource != nullptr)
105 {
106 std::unique_ptr<InputStream> in (inputSource->createInputStream());
107
108 if (in != nullptr)
109 {
111 data.writeFromInputStream (*in, onlyReadOuterDocumentElement ? 8192 : -1);
112
113 #if JUCE_STRING_UTF_TYPE == 8
114 if (data.getDataSize() > 2)
115 {
116 data.writeByte (0);
117 auto* text = static_cast<const char*> (data.getData());
118
121 {
122 originalText = data.toString();
123 }
124 else
125 {
127 text += 3;
128
129 // parse the input buffer directly to avoid copying it all to a string..
130 return parseDocumentElement (String::CharPointerType (text), onlyReadOuterDocumentElement);
131 }
132 }
133 #else
134 originalText = data.toString();
135 #endif
136 }
137 }
138
139 return parseDocumentElement (originalText.getCharPointer(), onlyReadOuterDocumentElement);
140}
141
143{
144 return lastError;
145}
146
147void XmlDocument::setLastError (const String& desc, const bool carryOn)
148{
149 lastError = desc;
150 errorOccurred = ! carryOn;
151}
152
153String XmlDocument::getFileContents (const String& filename) const
154{
155 if (inputSource != nullptr)
156 {
157 std::unique_ptr<InputStream> in (inputSource->createInputStreamFor (filename.trim().unquoted()));
158
159 if (in != nullptr)
160 return in->readEntireStreamAsString();
161 }
162
163 return {};
164}
165
166juce_wchar XmlDocument::readNextChar() noexcept
167{
168 auto c = input.getAndAdvance();
169
170 if (c == 0)
171 {
172 outOfData = true;
173 --input;
174 }
175
176 return c;
177}
178
179XmlElement* XmlDocument::parseDocumentElement (String::CharPointerType textToParse,
180 const bool onlyReadOuterDocumentElement)
181{
182 input = textToParse;
183 errorOccurred = false;
184 outOfData = false;
185 needToLoadDTD = true;
186
187 if (textToParse.isEmpty())
188 {
189 lastError = "not enough input";
190 }
191 else if (! parseHeader())
192 {
193 lastError = "malformed header";
194 }
195 else if (! parseDTD())
196 {
197 lastError = "malformed DTD";
198 }
199 else
200 {
201 lastError.clear();
202 std::unique_ptr<XmlElement> result (readNextElement (! onlyReadOuterDocumentElement));
203
204 if (! errorOccurred)
205 return result.release();
206 }
207
208 return nullptr;
209}
210
211bool XmlDocument::parseHeader()
212{
213 skipNextWhiteSpace();
214
215 if (CharacterFunctions::compareUpTo (input, CharPointer_ASCII ("<?xml"), 5) == 0)
216 {
217 auto headerEnd = CharacterFunctions::find (input, CharPointer_ASCII ("?>"));
218
219 if (headerEnd.isEmpty())
220 return false;
221
222 #if JUCE_DEBUG
223 auto encoding = String (input, headerEnd)
224 .fromFirstOccurrenceOf ("encoding", false, true)
225 .fromFirstOccurrenceOf ("=", false, false)
226 .fromFirstOccurrenceOf ("\"", false, false)
227 .upToFirstOccurrenceOf ("\"", false, false)
228 .trim();
229
230 /* If you load an XML document with a non-UTF encoding type, it may have been
231 loaded wrongly.. Since all the files are read via the normal juce file streams,
232 they're treated as UTF-8, so by the time it gets to the parser, the encoding will
233 have been lost. Best plan is to stick to utf-8 or if you have specific files to
234 read, use your own code to convert them to a unicode String, and pass that to the
235 XML parser.
236 */
237 jassert (encoding.isEmpty() || encoding.startsWithIgnoreCase ("utf-"));
238 #endif
239
240 input = headerEnd + 2;
241 skipNextWhiteSpace();
242 }
243
244 return true;
245}
246
247bool XmlDocument::parseDTD()
248{
249 if (CharacterFunctions::compareUpTo (input, CharPointer_ASCII ("<!DOCTYPE"), 9) == 0)
250 {
251 input += 9;
252 auto dtdStart = input;
253
254 for (int n = 1; n > 0;)
255 {
256 auto c = readNextChar();
257
258 if (outOfData)
259 return false;
260
261 if (c == '<')
262 ++n;
263 else if (c == '>')
264 --n;
265 }
266
267 dtdText = String (dtdStart, input - 1).trim();
268 }
269
270 return true;
271}
272
273void XmlDocument::skipNextWhiteSpace()
274{
275 for (;;)
276 {
277 input = input.findEndOfWhitespace();
278
279 if (input.isEmpty())
280 {
281 outOfData = true;
282 break;
283 }
284
285 if (*input == '<')
286 {
287 if (input[1] == '!'
288 && input[2] == '-'
289 && input[3] == '-')
290 {
291 input += 4;
292 auto closeComment = input.indexOf (CharPointer_ASCII ("-->"));
293
294 if (closeComment < 0)
295 {
296 outOfData = true;
297 break;
298 }
299
300 input += closeComment + 3;
301 continue;
302 }
303
304 if (input[1] == '?')
305 {
306 input += 2;
307 auto closeBracket = input.indexOf (CharPointer_ASCII ("?>"));
308
309 if (closeBracket < 0)
310 {
311 outOfData = true;
312 break;
313 }
314
315 input += closeBracket + 2;
316 continue;
317 }
318 }
319
320 break;
321 }
322}
323
324void XmlDocument::readQuotedString (String& result)
325{
326 auto quote = readNextChar();
327
328 while (! outOfData)
329 {
330 auto c = readNextChar();
331
332 if (c == quote)
333 break;
334
335 --input;
336
337 if (c == '&')
338 {
339 readEntity (result);
340 }
341 else
342 {
343 auto start = input;
344
345 for (;;)
346 {
347 auto character = *input;
348
349 if (character == quote)
350 {
351 result.appendCharPointer (start, input);
352 ++input;
353 return;
354 }
355
356 if (character == '&')
357 {
358 result.appendCharPointer (start, input);
359 break;
360 }
361
362 if (character == 0)
363 {
364 setLastError ("unmatched quotes", false);
365 outOfData = true;
366 break;
367 }
368
369 ++input;
370 }
371 }
372 }
373}
374
375XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
376{
377 XmlElement* node = nullptr;
378 skipNextWhiteSpace();
379
380 if (outOfData)
381 return nullptr;
382
383 if (*input == '<')
384 {
385 ++input;
386 auto endOfToken = XmlIdentifierChars::findEndOfToken (input);
387
388 if (endOfToken == input)
389 {
390 // no tag name - but allow for a gap after the '<' before giving an error
391 skipNextWhiteSpace();
392 endOfToken = XmlIdentifierChars::findEndOfToken (input);
393
394 if (endOfToken == input)
395 {
396 setLastError ("tag name missing", false);
397 return node;
398 }
399 }
400
401 node = new XmlElement (input, endOfToken);
402 input = endOfToken;
403 LinkedListPointer<XmlElement::XmlAttributeNode>::Appender attributeAppender (node->attributes);
404
405 // look for attributes
406 for (;;)
407 {
408 skipNextWhiteSpace();
409 auto c = *input;
410
411 // empty tag..
412 if (c == '/' && input[1] == '>')
413 {
414 input += 2;
415 break;
416 }
417
418 // parse the guts of the element..
419 if (c == '>')
420 {
421 ++input;
422
423 if (alsoParseSubElements)
424 readChildElements (*node);
425
426 break;
427 }
428
429 // get an attribute..
430 if (XmlIdentifierChars::isIdentifierChar (c))
431 {
432 auto attNameEnd = XmlIdentifierChars::findEndOfToken (input);
433
434 if (attNameEnd != input)
435 {
436 auto attNameStart = input;
437 input = attNameEnd;
438 skipNextWhiteSpace();
439
440 if (readNextChar() == '=')
441 {
442 skipNextWhiteSpace();
443 auto nextChar = *input;
444
445 if (nextChar == '"' || nextChar == '\'')
446 {
447 auto* newAtt = new XmlElement::XmlAttributeNode (attNameStart, attNameEnd);
448 readQuotedString (newAtt->value);
449 attributeAppender.append (newAtt);
450 continue;
451 }
452 }
453 else
454 {
455 setLastError ("expected '=' after attribute '"
456 + String (attNameStart, attNameEnd) + "'", false);
457 return node;
458 }
459 }
460 }
461 else
462 {
463 if (! outOfData)
464 setLastError ("illegal character found in " + node->getTagName() + ": '" + c + "'", false);
465 }
466
467 break;
468 }
469 }
470
471 return node;
472}
473
474void XmlDocument::readChildElements (XmlElement& parent)
475{
476 LinkedListPointer<XmlElement>::Appender childAppender (parent.firstChildElement);
477
478 for (;;)
479 {
480 auto preWhitespaceInput = input;
481 skipNextWhiteSpace();
482
483 if (outOfData)
484 {
485 setLastError ("unmatched tags", false);
486 break;
487 }
488
489 if (*input == '<')
490 {
491 auto c1 = input[1];
492
493 if (c1 == '/')
494 {
495 // our close tag..
496 auto closeTag = input.indexOf ((juce_wchar) '>');
497
498 if (closeTag >= 0)
499 input += closeTag + 1;
500
501 break;
502 }
503
504 if (c1 == '!' && CharacterFunctions::compareUpTo (input + 2, CharPointer_ASCII ("[CDATA["), 7) == 0)
505 {
506 input += 9;
507 auto inputStart = input;
508
509 for (;;)
510 {
511 auto c0 = *input;
512
513 if (c0 == 0)
514 {
515 setLastError ("unterminated CDATA section", false);
516 outOfData = true;
517 break;
518 }
519
520 if (c0 == ']' && input[1] == ']' && input[2] == '>')
521 {
522 childAppender.append (XmlElement::createTextElement (String (inputStart, input)));
523 input += 3;
524 break;
525 }
526
527 ++input;
528 }
529 }
530 else
531 {
532 // this is some other element, so parse and add it..
533 if (auto* n = readNextElement (true))
534 childAppender.append (n);
535 else
536 break;
537 }
538 }
539 else // must be a character block
540 {
541 input = preWhitespaceInput; // roll back to include the leading whitespace
542 MemoryOutputStream textElementContent;
543 bool contentShouldBeUsed = ! ignoreEmptyTextElements;
544
545 for (;;)
546 {
547 auto c = *input;
548
549 if (c == '<')
550 {
551 if (input[1] == '!' && input[2] == '-' && input[3] == '-')
552 {
553 input += 4;
554 auto closeComment = input.indexOf (CharPointer_ASCII ("-->"));
555
556 if (closeComment < 0)
557 {
558 setLastError ("unterminated comment", false);
559 outOfData = true;
560 return;
561 }
562
563 input += closeComment + 3;
564 continue;
565 }
566
567 break;
568 }
569
570 if (c == 0)
571 {
572 setLastError ("unmatched tags", false);
573 outOfData = true;
574 return;
575 }
576
577 if (c == '&')
578 {
579 String entity;
580 readEntity (entity);
581
582 if (entity.startsWithChar ('<') && entity [1] != 0)
583 {
584 auto oldInput = input;
585 auto oldOutOfData = outOfData;
586
587 input = entity.getCharPointer();
588 outOfData = false;
589
590 while (auto* n = readNextElement (true))
591 childAppender.append (n);
592
593 input = oldInput;
594 outOfData = oldOutOfData;
595 }
596 else
597 {
598 textElementContent << entity;
599 contentShouldBeUsed = contentShouldBeUsed || entity.containsNonWhitespaceChars();
600 }
601 }
602 else
603 {
604 for (;; ++input)
605 {
606 auto nextChar = *input;
607
608 if (nextChar == '\r')
609 {
610 nextChar = '\n';
611
612 if (input[1] == '\n')
613 continue;
614 }
615
616 if (nextChar == '<' || nextChar == '&')
617 break;
618
619 if (nextChar == 0)
620 {
621 setLastError ("unmatched tags", false);
622 outOfData = true;
623 return;
624 }
625
626 textElementContent.appendUTF8Char (nextChar);
627 contentShouldBeUsed = contentShouldBeUsed || ! CharacterFunctions::isWhitespace (nextChar);
628 }
629 }
630 }
631
632 if (contentShouldBeUsed)
633 childAppender.append (XmlElement::createTextElement (textElementContent.toUTF8()));
634 }
635 }
636}
637
638void XmlDocument::readEntity (String& result)
639{
640 // skip over the ampersand
641 ++input;
642
643 if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("amp;"), 4) == 0)
644 {
645 input += 4;
646 result += '&';
647 }
648 else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("quot;"), 5) == 0)
649 {
650 input += 5;
651 result += '"';
652 }
653 else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("apos;"), 5) == 0)
654 {
655 input += 5;
656 result += '\'';
657 }
658 else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("lt;"), 3) == 0)
659 {
660 input += 3;
661 result += '<';
662 }
663 else if (input.compareIgnoreCaseUpTo (CharPointer_ASCII ("gt;"), 3) == 0)
664 {
665 input += 3;
666 result += '>';
667 }
668 else if (*input == '#')
669 {
670 int charCode = 0;
671 ++input;
672
673 if (*input == 'x' || *input == 'X')
674 {
675 ++input;
676 int numChars = 0;
677
678 while (input[0] != ';')
679 {
680 auto hexValue = CharacterFunctions::getHexDigitValue (input[0]);
681
682 if (hexValue < 0 || ++numChars > 8)
683 {
684 setLastError ("illegal escape sequence", true);
685 break;
686 }
687
688 charCode = (charCode << 4) | hexValue;
689 ++input;
690 }
691
692 ++input;
693 }
694 else if (input[0] >= '0' && input[0] <= '9')
695 {
696 int numChars = 0;
697
698 while (input[0] != ';')
699 {
700 if (++numChars > 12)
701 {
702 setLastError ("illegal escape sequence", true);
703 break;
704 }
705
706 charCode = charCode * 10 + ((int) input[0] - '0');
707 ++input;
708 }
709
710 ++input;
711 }
712 else
713 {
714 setLastError ("illegal escape sequence", true);
715 result += '&';
716 return;
717 }
718
719 result << (juce_wchar) charCode;
720 }
721 else
722 {
723 auto entityNameStart = input;
724 auto closingSemiColon = input.indexOf ((juce_wchar) ';');
725
726 if (closingSemiColon < 0)
727 {
728 outOfData = true;
729 result += '&';
730 }
731 else
732 {
733 input += closingSemiColon + 1;
734 result += expandExternalEntity (String (entityNameStart, (size_t) closingSemiColon));
735 }
736 }
737}
738
739String XmlDocument::expandEntity (const String& ent)
740{
741 if (ent.equalsIgnoreCase ("amp")) return String::charToString ('&');
742 if (ent.equalsIgnoreCase ("quot")) return String::charToString ('"');
743 if (ent.equalsIgnoreCase ("apos")) return String::charToString ('\'');
744 if (ent.equalsIgnoreCase ("lt")) return String::charToString ('<');
745 if (ent.equalsIgnoreCase ("gt")) return String::charToString ('>');
746
747 if (ent[0] == '#')
748 {
749 auto char1 = ent[1];
750
751 if (char1 == 'x' || char1 == 'X')
752 return String::charToString (static_cast<juce_wchar> (ent.substring (2).getHexValue32()));
753
754 if (char1 >= '0' && char1 <= '9')
755 return String::charToString (static_cast<juce_wchar> (ent.substring (1).getIntValue()));
756
757 setLastError ("illegal escape sequence", false);
758 return String::charToString ('&');
759 }
760
761 return expandExternalEntity (ent);
762}
763
764String XmlDocument::expandExternalEntity (const String& entity)
765{
766 if (needToLoadDTD)
767 {
768 if (dtdText.isNotEmpty())
769 {
770 dtdText = dtdText.trimCharactersAtEnd (">");
771 tokenisedDTD.addTokens (dtdText, true);
772
773 if (tokenisedDTD[tokenisedDTD.size() - 2].equalsIgnoreCase ("system")
774 && tokenisedDTD[tokenisedDTD.size() - 1].isQuotedString())
775 {
776 auto fn = tokenisedDTD[tokenisedDTD.size() - 1];
777
778 tokenisedDTD.clear();
779 tokenisedDTD.addTokens (getFileContents (fn), true);
780 }
781 else
782 {
783 tokenisedDTD.clear();
784 auto openBracket = dtdText.indexOfChar ('[');
785
786 if (openBracket > 0)
787 {
788 auto closeBracket = dtdText.lastIndexOfChar (']');
789
790 if (closeBracket > openBracket)
791 tokenisedDTD.addTokens (dtdText.substring (openBracket + 1,
792 closeBracket), true);
793 }
794 }
795
796 for (int i = tokenisedDTD.size(); --i >= 0;)
797 {
798 if (tokenisedDTD[i].startsWithChar ('%')
799 && tokenisedDTD[i].endsWithChar (';'))
800 {
801 auto parsed = getParameterEntity (tokenisedDTD[i].substring (1, tokenisedDTD[i].length() - 1));
802 StringArray newToks;
803 newToks.addTokens (parsed, true);
804
805 tokenisedDTD.remove (i);
806
807 for (int j = newToks.size(); --j >= 0;)
808 tokenisedDTD.insert (i, newToks[j]);
809 }
810 }
811 }
812
813 needToLoadDTD = false;
814 }
815
816 for (int i = 0; i < tokenisedDTD.size(); ++i)
817 {
818 if (tokenisedDTD[i] == entity)
819 {
820 if (tokenisedDTD[i - 1].equalsIgnoreCase ("<!entity"))
821 {
822 auto ent = tokenisedDTD [i + 1].trimCharactersAtEnd (">").trim().unquoted();
823
824 // check for sub-entities..
825 auto ampersand = ent.indexOfChar ('&');
826
827 while (ampersand >= 0)
828 {
829 auto semiColon = ent.indexOf (i + 1, ";");
830
831 if (semiColon < 0)
832 {
833 setLastError ("entity without terminating semi-colon", false);
834 break;
835 }
836
837 auto resolved = expandEntity (ent.substring (i + 1, semiColon));
838
839 ent = ent.substring (0, ampersand)
840 + resolved
841 + ent.substring (semiColon + 1);
842
843 ampersand = ent.indexOfChar (semiColon + 1, '&');
844 }
845
846 return ent;
847 }
848 }
849 }
850
851 setLastError ("unknown entity", true);
852 return entity;
853}
854
855String XmlDocument::getParameterEntity (const String& entity)
856{
857 for (int i = 0; i < tokenisedDTD.size(); ++i)
858 {
859 if (tokenisedDTD[i] == entity
860 && tokenisedDTD [i - 1] == "%"
861 && tokenisedDTD [i - 2].equalsIgnoreCase ("<!entity"))
862 {
863 auto ent = tokenisedDTD [i + 1].trimCharactersAtEnd (">");
864
865 if (ent.equalsIgnoreCase ("system"))
866 return getFileContents (tokenisedDTD [i + 2].trimCharactersAtEnd (">"));
867
868 return ent.trim().unquoted();
869 }
870 }
871
872 return entity;
873}
874
875}
static bool isByteOrderMarkBigEndian(const void *possibleByteOrder) noexcept
Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (big endian).
static bool isByteOrderMarkLittleEndian(const void *possibleByteOrder) noexcept
Returns true if the first pair of bytes in this pointer are the UTF16 byte-order mark (little endian)...
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
int compareIgnoreCaseUpTo(const CharPointer other, const int maxChars) const noexcept
Compares this string with another one, up to a specified number of characters.
juce_wchar getAndAdvance() noexcept
Returns the character that this pointer is currently pointing to, and then advances the pointer to po...
bool isEmpty() const noexcept
Returns true if this pointer is pointing to a null character.
int indexOf(const CharPointer stringToFind) const noexcept
Returns the character index of a substring, or -1 if it isn't found.
static bool isByteOrderMark(const void *possibleByteOrder) noexcept
Returns true if the first three bytes in this pointer are the UTF8 byte-order mark (BOM).
CharPointer_UTF8 findEndOfWhitespace() const noexcept
Returns the first non-whitespace character in the string.
static int getHexDigitValue(juce_wchar digit) noexcept
Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit.
static bool isWhitespace(char character) noexcept
Checks whether a character is whitespace.
static bool isLetterOrDigit(char character) noexcept
Checks whether a character is alphabetic or numeric.
static CharPointerType1 find(CharPointerType1 textToSearch, const CharPointerType2 substringToLookFor) noexcept
Returns a pointer to the first occurrence of a substring in a string.
static int compareUpTo(CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
Compares two null-terminated character strings, up to a given number of characters.
A type of InputSource that represents a normal file.
Represents a local file or directory.
Definition juce_File.h:45
A lightweight object that can create a stream to read some kind of resource.
Writes data to an internal memory buffer, which grows as required.
const void * getData() const noexcept
Returns a pointer to the data that has been written to the stream.
String toString() const
Attempts to detect the encoding of the data and convert it to a string.
size_t getDataSize() const noexcept
Returns the number of bytes of data that have been written to the stream.
int64 writeFromInputStream(InputStream &, int64 maxNumBytesToWrite) override
Reads data from an input stream and writes it to this stream.
virtual bool writeByte(char byte)
Writes a single byte to the stream.
void insert(int index, String stringToAdd)
Inserts a string into the array.
void clear()
Removes all elements from the array.
int size() const noexcept
Returns the number of strings in the array.
void trim()
Deletes any whitespace characters from the starts and ends of all the strings.
void remove(int index)
Removes a string from the array.
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Breaks up a string into tokens and adds them to this array.
The JUCE String class!
Definition juce_String.h:43
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
int indexOfChar(juce_wchar characterToLookFor) const noexcept
Searches for a character inside this string.
String trim() const
Returns a copy of this string with any whitespace characters removed from the start and end.
bool isEmpty() const noexcept
Returns true if the string contains no characters.
void clear() noexcept
Resets this string to be empty.
int lastIndexOfChar(juce_wchar character) const noexcept
Searches for a character inside this string (working backwards from the end of the string).
String trimCharactersAtEnd(StringRef charactersToTrim) const
Returns a copy of this string, having removed a specified set of characters from its end.
static String charToString(juce_wchar character)
Creates a string from a single character.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
CharPointer_UTF8 CharPointerType
This is the character encoding type used internally to store the string.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
Parses a text-based XML document and creates an XmlElement object from it.
const String & getLastParseError() const noexcept
Returns the parsing error that occurred the last time getDocumentElement was called.
static XmlElement * parse(const File &file)
A handy static method that parses a file.
XmlDocument(const String &documentText)
Creates an XmlDocument from the xml text.
void setInputSource(InputSource *newSource) noexcept
Sets an input source object to use for parsing documents that reference external entities.
XmlElement * getDocumentElement(bool onlyReadOuterDocumentElement=false)
Creates an XmlElement object to represent the main document node.
~XmlDocument()
Destructor.
void setEmptyTextElementsIgnored(bool shouldBeIgnored) noexcept
Sets a flag to change the treatment of empty text elements.
Used to build a tree of elements representing an XML document.
static XmlElement * createTextElement(const String &text)
Creates a text element that can be added to a parent element.