OpenShot Library | libopenshot-audio 0.2.0
juce_File.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
26File::File (const String& fullPathName)
27 : fullPath (parseAbsolutePath (fullPathName))
28{
29}
30
32{
33 File f;
34 f.fullPath = path;
35 return f;
36}
37
38File::File (const File& other)
39 : fullPath (other.fullPath)
40{
41}
42
44{
45 fullPath = parseAbsolutePath (newPath);
46 return *this;
47}
48
50{
51 fullPath = other.fullPath;
52 return *this;
53}
54
55File::File (File&& other) noexcept
56 : fullPath (std::move (other.fullPath))
57{
58}
59
60File& File::operator= (File&& other) noexcept
61{
62 fullPath = std::move (other.fullPath);
63 return *this;
64}
65
66JUCE_DECLARE_DEPRECATED_STATIC (const File File::nonexistent{};)
67
68//==============================================================================
69static String removeEllipsis (const String& path)
70{
71 // This will quickly find both /../ and /./ at the expense of a minor
72 // false-positive performance hit when path elements end in a dot.
73 #if JUCE_WINDOWS
74 if (path.contains (".\\"))
75 #else
76 if (path.contains ("./"))
77 #endif
78 {
79 StringArray toks;
80 toks.addTokens (path, File::getSeparatorString(), {});
81 bool anythingChanged = false;
82
83 for (int i = 1; i < toks.size(); ++i)
84 {
85 auto& t = toks[i];
86
87 if (t == ".." && toks[i - 1] != "..")
88 {
89 anythingChanged = true;
90 toks.removeRange (i - 1, 2);
91 i = jmax (0, i - 2);
92 }
93 else if (t == ".")
94 {
95 anythingChanged = true;
96 toks.remove (i--);
97 }
98 }
99
100 if (anythingChanged)
101 return toks.joinIntoString (File::getSeparatorString());
102 }
103
104 return path;
105}
106
107bool File::isRoot() const
108{
109 return fullPath.isNotEmpty() && *this == getParentDirectory();
110}
111
112String File::parseAbsolutePath (const String& p)
113{
114 if (p.isEmpty())
115 return {};
116
117#if JUCE_WINDOWS
118 // Windows..
119 auto path = removeEllipsis (p.replaceCharacter ('/', '\\'));
120
121 if (path.startsWithChar (getSeparatorChar()))
122 {
123 if (path[1] != getSeparatorChar())
124 {
125 /* When you supply a raw string to the File object constructor, it must be an absolute path.
126 If you're trying to parse a string that may be either a relative path or an absolute path,
127 you MUST provide a context against which the partial path can be evaluated - you can do
128 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
129 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
130 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
131 */
132 jassertfalse;
133
135 }
136 }
137 else if (! path.containsChar (':'))
138 {
139 /* When you supply a raw string to the File object constructor, it must be an absolute path.
140 If you're trying to parse a string that may be either a relative path or an absolute path,
141 you MUST provide a context against which the partial path can be evaluated - you can do
142 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
143 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
144 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
145 */
146 jassertfalse;
147
149 }
150#else
151 // Mac or Linux..
152
153 // Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here
154 // to catch anyone who's trying to run code that was written on Windows with hard-coded path names.
155 // If that's why you've ended up here, use File::getChildFile() to build your paths instead.
156 jassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\')));
157
158 auto path = removeEllipsis (p);
159
160 if (path.startsWithChar ('~'))
161 {
162 if (path[1] == getSeparatorChar() || path[1] == 0)
163 {
164 // expand a name of the form "~/abc"
166 + path.substring (1);
167 }
168 else
169 {
170 // expand a name of type "~dave/abc"
171 auto userName = path.substring (1).upToFirstOccurrenceOf ("/", false, false);
172
173 if (auto* pw = getpwnam (userName.toUTF8()))
174 path = addTrailingSeparator (pw->pw_dir) + path.fromFirstOccurrenceOf ("/", false, false);
175 }
176 }
177 else if (! path.startsWithChar (getSeparatorChar()))
178 {
179 #if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
180 if (! (path.startsWith ("./") || path.startsWith ("../")))
181 {
182 /* When you supply a raw string to the File object constructor, it must be an absolute path.
183 If you're trying to parse a string that may be either a relative path or an absolute path,
184 you MUST provide a context against which the partial path can be evaluated - you can do
185 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
186 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
187 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
188 */
189 jassertfalse;
190
191 #if JUCE_LOG_ASSERTIONS
192 Logger::writeToLog ("Illegal absolute path: " + path);
193 #endif
194 }
195 #endif
196
198 }
199#endif
200
201 while (path.endsWithChar (getSeparatorChar()) && path != getSeparatorString()) // careful not to turn a single "/" into an empty string.
202 path = path.dropLastCharacters (1);
203
204 return path;
205}
206
208{
209 return path.endsWithChar (getSeparatorChar()) ? path
210 : path + getSeparatorChar();
211}
212
213//==============================================================================
214#if JUCE_LINUX
215 #define NAMES_ARE_CASE_SENSITIVE 1
216#endif
217
219{
220 #if NAMES_ARE_CASE_SENSITIVE
221 return true;
222 #else
223 return false;
224 #endif
225}
226
227static int compareFilenames (const String& name1, const String& name2) noexcept
228{
229 #if NAMES_ARE_CASE_SENSITIVE
230 return name1.compare (name2);
231 #else
232 return name1.compareIgnoreCase (name2);
233 #endif
234}
235
236bool File::operator== (const File& other) const { return compareFilenames (fullPath, other.fullPath) == 0; }
237bool File::operator!= (const File& other) const { return compareFilenames (fullPath, other.fullPath) != 0; }
238bool File::operator< (const File& other) const { return compareFilenames (fullPath, other.fullPath) < 0; }
239bool File::operator> (const File& other) const { return compareFilenames (fullPath, other.fullPath) > 0; }
240
241//==============================================================================
242bool File::setReadOnly (const bool shouldBeReadOnly,
243 const bool applyRecursively) const
244{
245 bool worked = true;
246
247 if (applyRecursively && isDirectory())
248 for (auto& f : findChildFiles (File::findFilesAndDirectories, false))
249 worked = f.setReadOnly (shouldBeReadOnly, true) && worked;
250
251 return setFileReadOnlyInternal (shouldBeReadOnly) && worked;
252}
253
254bool File::setExecutePermission (bool shouldBeExecutable) const
255{
256 return setFileExecutableInternal (shouldBeExecutable);
257}
258
259bool File::deleteRecursively (bool followSymlinks) const
260{
261 bool worked = true;
262
263 if (isDirectory() && (followSymlinks || ! isSymbolicLink()))
264 for (auto& f : findChildFiles (File::findFilesAndDirectories, false))
265 worked = f.deleteRecursively (followSymlinks) && worked;
266
267 return deleteFile() && worked;
268}
269
270bool File::moveFileTo (const File& newFile) const
271{
272 if (newFile.fullPath == fullPath)
273 return true;
274
275 if (! exists())
276 return false;
277
278 #if ! NAMES_ARE_CASE_SENSITIVE
279 if (*this != newFile)
280 #endif
281 if (! newFile.deleteFile())
282 return false;
283
284 return moveInternal (newFile);
285}
286
287bool File::copyFileTo (const File& newFile) const
288{
289 return (*this == newFile)
290 || (exists() && newFile.deleteFile() && copyInternal (newFile));
291}
292
293bool File::replaceFileIn (const File& newFile) const
294{
295 if (newFile.fullPath == fullPath)
296 return true;
297
298 if (! newFile.exists())
299 return moveFileTo (newFile);
300
301 if (! replaceInternal (newFile))
302 return false;
303
304 deleteFile();
305 return true;
306}
307
308bool File::copyDirectoryTo (const File& newDirectory) const
309{
310 if (isDirectory() && newDirectory.createDirectory())
311 {
312 for (auto& f : findChildFiles (File::findFiles, false))
313 if (! f.copyFileTo (newDirectory.getChildFile (f.getFileName())))
314 return false;
315
316 for (auto& f : findChildFiles (File::findDirectories, false))
317 if (! f.copyDirectoryTo (newDirectory.getChildFile (f.getFileName())))
318 return false;
319
320 return true;
321 }
322
323 return false;
324}
325
326//==============================================================================
327String File::getPathUpToLastSlash() const
328{
329 auto lastSlash = fullPath.lastIndexOfChar (getSeparatorChar());
330
331 if (lastSlash > 0)
332 return fullPath.substring (0, lastSlash);
333
334 if (lastSlash == 0)
335 return getSeparatorString();
336
337 return fullPath;
338}
339
341{
342 return createFileWithoutCheckingPath (getPathUpToLastSlash());
343}
344
345//==============================================================================
347{
348 return fullPath.substring (fullPath.lastIndexOfChar (getSeparatorChar()) + 1);
349}
350
352{
353 auto lastSlash = fullPath.lastIndexOfChar (getSeparatorChar()) + 1;
354 auto lastDot = fullPath.lastIndexOfChar ('.');
355
356 if (lastDot > lastSlash)
357 return fullPath.substring (lastSlash, lastDot);
358
359 return fullPath.substring (lastSlash);
360}
361
362bool File::isAChildOf (const File& potentialParent) const
363{
364 if (potentialParent.fullPath.isEmpty())
365 return false;
366
367 auto ourPath = getPathUpToLastSlash();
368
369 if (compareFilenames (potentialParent.fullPath, ourPath) == 0)
370 return true;
371
372 if (potentialParent.fullPath.length() >= ourPath.length())
373 return false;
374
375 return getParentDirectory().isAChildOf (potentialParent);
376}
377
378int File::hashCode() const { return fullPath.hashCode(); }
379int64 File::hashCode64() const { return fullPath.hashCode64(); }
380
381//==============================================================================
383{
384 auto firstChar = *(path.text);
385
386 return firstChar == getSeparatorChar()
387 #if JUCE_WINDOWS
388 || (firstChar != 0 && path.text[1] == ':');
389 #else
390 || firstChar == '~';
391 #endif
392}
393
395{
396 auto r = relativePath.text;
397
398 if (isAbsolutePath (r))
399 return File (String (r));
400
401 #if JUCE_WINDOWS
402 if (r.indexOf ((juce_wchar) '/') >= 0)
403 return getChildFile (String (r).replaceCharacter ('/', '\\'));
404 #endif
405
406 auto path = fullPath;
407 auto separatorChar = getSeparatorChar();
408
409 while (*r == '.')
410 {
411 auto lastPos = r;
412 auto secondChar = *++r;
413
414 if (secondChar == '.') // remove "../"
415 {
416 auto thirdChar = *++r;
417
418 if (thirdChar == separatorChar || thirdChar == 0)
419 {
420 auto lastSlash = path.lastIndexOfChar (separatorChar);
421
422 if (lastSlash >= 0)
423 path = path.substring (0, lastSlash);
424
425 while (*r == separatorChar) // ignore duplicate slashes
426 ++r;
427 }
428 else
429 {
430 r = lastPos;
431 break;
432 }
433 }
434 else if (secondChar == separatorChar || secondChar == 0) // remove "./"
435 {
436 while (*r == separatorChar) // ignore duplicate slashes
437 ++r;
438 }
439 else
440 {
441 r = lastPos;
442 break;
443 }
444 }
445
446 path = addTrailingSeparator (path);
447 path.appendCharPointer (r);
448 return File (path);
449}
450
452{
453 return getParentDirectory().getChildFile (fileName);
454}
455
456//==============================================================================
458{
459 const char* suffix;
460 double divisor = 0;
461
462 if (bytes == 1) { suffix = " byte"; }
463 else if (bytes < 1024) { suffix = " bytes"; }
464 else if (bytes < 1024 * 1024) { suffix = " KB"; divisor = 1024.0; }
465 else if (bytes < 1024 * 1024 * 1024) { suffix = " MB"; divisor = 1024.0 * 1024.0; }
466 else { suffix = " GB"; divisor = 1024.0 * 1024.0 * 1024.0; }
467
468 return (divisor > 0 ? String (bytes / divisor, 1) : String (bytes)) + suffix;
469}
470
471//==============================================================================
473{
474 if (exists())
475 return Result::ok();
476
477 auto parentDir = getParentDirectory();
478
479 if (parentDir == *this)
480 return Result::fail ("Cannot create parent directory");
481
482 auto r = parentDir.createDirectory();
483
484 if (r.wasOk())
485 {
486 FileOutputStream fo (*this, 8);
487 r = fo.getStatus();
488 }
489
490 return r;
491}
492
494{
495 if (isDirectory())
496 return Result::ok();
497
498 auto parentDir = getParentDirectory();
499
500 if (parentDir == *this)
501 return Result::fail ("Cannot create parent directory");
502
503 auto r = parentDir.createDirectory();
504
505 if (r.wasOk())
506 r = createDirectoryInternal (fullPath.trimCharactersAtEnd (getSeparatorString()));
507
508 return r;
509}
510
511//==============================================================================
512Time File::getLastModificationTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (m); }
513Time File::getLastAccessTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (a); }
514Time File::getCreationTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (c); }
515
516bool File::setLastModificationTime (Time t) const { return setFileTimesInternal (t.toMilliseconds(), 0, 0); }
517bool File::setLastAccessTime (Time t) const { return setFileTimesInternal (0, t.toMilliseconds(), 0); }
518bool File::setCreationTime (Time t) const { return setFileTimesInternal (0, 0, t.toMilliseconds()); }
519
520//==============================================================================
521bool File::loadFileAsData (MemoryBlock& destBlock) const
522{
523 if (! existsAsFile())
524 return false;
525
526 FileInputStream in (*this);
527 return in.openedOk() && getSize() == (int64) in.readIntoMemoryBlock (destBlock);
528}
529
531{
532 if (! existsAsFile())
533 return {};
534
535 FileInputStream in (*this);
536 return in.openedOk() ? in.readEntireStreamAsString()
537 : String();
538}
539
540void File::readLines (StringArray& destLines) const
541{
542 destLines.addLines (loadFileAsString());
543}
544
545//==============================================================================
546Array<File> File::findChildFiles (int whatToLookFor, bool searchRecursively, const String& wildcard) const
547{
548 Array<File> results;
549 findChildFiles (results, whatToLookFor, searchRecursively, wildcard);
550 return results;
551}
552
553int File::findChildFiles (Array<File>& results, int whatToLookFor, bool searchRecursively, const String& wildcard) const
554{
555 int total = 0;
556
557 for (DirectoryIterator di (*this, searchRecursively, wildcard, whatToLookFor); di.next();)
558 {
559 results.add (di.getFile());
560 ++total;
561 }
562
563 return total;
564}
565
566int File::getNumberOfChildFiles (const int whatToLookFor, const String& wildCardPattern) const
567{
568 int total = 0;
569
570 for (DirectoryIterator di (*this, false, wildCardPattern, whatToLookFor); di.next();)
571 ++total;
572
573 return total;
574}
575
577{
578 if (! isDirectory())
579 return false;
580
581 DirectoryIterator di (*this, false, "*", findDirectories);
582 return di.next();
583}
584
585//==============================================================================
587 const String& suffix,
588 bool putNumbersInBrackets) const
589{
590 auto f = getChildFile (suggestedPrefix + suffix);
591
592 if (f.exists())
593 {
594 int number = 1;
595 auto prefix = suggestedPrefix;
596
597 // remove any bracketed numbers that may already be on the end..
598 if (prefix.trim().endsWithChar (')'))
599 {
600 putNumbersInBrackets = true;
601
602 auto openBracks = prefix.lastIndexOfChar ('(');
603 auto closeBracks = prefix.lastIndexOfChar (')');
604
605 if (openBracks > 0
606 && closeBracks > openBracks
607 && prefix.substring (openBracks + 1, closeBracks).containsOnly ("0123456789"))
608 {
609 number = prefix.substring (openBracks + 1, closeBracks).getIntValue();
610 prefix = prefix.substring (0, openBracks);
611 }
612 }
613
614 do
615 {
616 auto newName = prefix;
617
618 if (putNumbersInBrackets)
619 {
620 newName << '(' << ++number << ')';
621 }
622 else
623 {
624 if (CharacterFunctions::isDigit (prefix.getLastCharacter()))
625 newName << '_'; // pad with an underscore if the name already ends in a digit
626
627 newName << ++number;
628 }
629
630 f = getChildFile (newName + suffix);
631
632 } while (f.exists());
633 }
634
635 return f;
636}
637
638File File::getNonexistentSibling (const bool putNumbersInBrackets) const
639{
640 if (! exists())
641 return *this;
642
645 putNumbersInBrackets);
646}
647
648//==============================================================================
650{
651 auto indexOfDot = fullPath.lastIndexOfChar ('.');
652
653 if (indexOfDot > fullPath.lastIndexOfChar (getSeparatorChar()))
654 return fullPath.substring (indexOfDot);
655
656 return {};
657}
658
659bool File::hasFileExtension (StringRef possibleSuffix) const
660{
661 if (possibleSuffix.isEmpty())
662 return fullPath.lastIndexOfChar ('.') <= fullPath.lastIndexOfChar (getSeparatorChar());
663
664 auto semicolon = possibleSuffix.text.indexOf ((juce_wchar) ';');
665
666 if (semicolon >= 0)
667 return hasFileExtension (String (possibleSuffix.text).substring (0, semicolon).trimEnd())
668 || hasFileExtension ((possibleSuffix.text + (semicolon + 1)).findEndOfWhitespace());
669
670 if (fullPath.endsWithIgnoreCase (possibleSuffix))
671 {
672 if (possibleSuffix.text[0] == '.')
673 return true;
674
675 auto dotPos = fullPath.length() - possibleSuffix.length() - 1;
676
677 if (dotPos >= 0)
678 return fullPath[dotPos] == '.';
679 }
680
681 return false;
682}
683
685{
686 if (fullPath.isEmpty())
687 return {};
688
689 auto filePart = getFileName();
690
691 auto lastDot = filePart.lastIndexOfChar ('.');
692
693 if (lastDot >= 0)
694 filePart = filePart.substring (0, lastDot);
695
696 if (newExtension.isNotEmpty() && newExtension.text[0] != '.')
697 filePart << '.';
698
699 return getSiblingFile (filePart + newExtension);
700}
701
702//==============================================================================
703bool File::startAsProcess (const String& parameters) const
704{
705 return exists() && Process::openDocument (fullPath, parameters);
706}
707
708//==============================================================================
710{
711 std::unique_ptr<FileInputStream> fin (new FileInputStream (*this));
712
713 if (fin->openedOk())
714 return fin.release();
715
716 return nullptr;
717}
718
720{
721 std::unique_ptr<FileOutputStream> out (new FileOutputStream (*this, bufferSize));
722
723 return out->failedToOpen() ? nullptr
724 : out.release();
725}
726
727//==============================================================================
728bool File::appendData (const void* const dataToAppend,
729 const size_t numberOfBytes) const
730{
731 jassert (((ssize_t) numberOfBytes) >= 0);
732
733 if (numberOfBytes == 0)
734 return true;
735
736 FileOutputStream out (*this, 8192);
737 return out.openedOk() && out.write (dataToAppend, numberOfBytes);
738}
739
740bool File::replaceWithData (const void* const dataToWrite,
741 const size_t numberOfBytes) const
742{
743 if (numberOfBytes == 0)
744 return deleteFile();
745
747 tempFile.getFile().appendData (dataToWrite, numberOfBytes);
748 return tempFile.overwriteTargetFileWithTemporary();
749}
750
751bool File::appendText (const String& text, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const
752{
753 FileOutputStream out (*this);
754
755 if (out.failedToOpen())
756 return false;
757
758 return out.writeText (text, asUnicode, writeHeaderBytes, lineFeed);
759}
760
761bool File::replaceWithText (const String& textToWrite, bool asUnicode, bool writeHeaderBytes, const char* lineFeed) const
762{
764 tempFile.getFile().appendText (textToWrite, asUnicode, writeHeaderBytes, lineFeed);
765 return tempFile.overwriteTargetFileWithTemporary();
766}
767
768bool File::hasIdenticalContentTo (const File& other) const
769{
770 if (other == *this)
771 return true;
772
773 if (getSize() == other.getSize() && existsAsFile() && other.existsAsFile())
774 {
775 FileInputStream in1 (*this), in2 (other);
776
777 if (in1.openedOk() && in2.openedOk())
778 {
779 const int bufferSize = 4096;
780 HeapBlock<char> buffer1 (bufferSize), buffer2 (bufferSize);
781
782 for (;;)
783 {
784 auto num1 = in1.read (buffer1, bufferSize);
785 auto num2 = in2.read (buffer2, bufferSize);
786
787 if (num1 != num2)
788 break;
789
790 if (num1 <= 0)
791 return true;
792
793 if (memcmp (buffer1, buffer2, (size_t) num1) != 0)
794 break;
795 }
796 }
797 }
798
799 return false;
800}
801
802//==============================================================================
804{
805 auto s = original;
806 String start;
807
808 if (s.isNotEmpty() && s[1] == ':')
809 {
810 start = s.substring (0, 2);
811 s = s.substring (2);
812 }
813
814 return start + s.removeCharacters ("\"#@,;:<>*^|?")
815 .substring (0, 1024);
816}
817
819{
820 auto s = original.removeCharacters ("\"#@,;:<>*^|?\\/");
821
822 const int maxLength = 128; // only the length of the filename, not the whole path
823 auto len = s.length();
824
825 if (len > maxLength)
826 {
827 auto lastDot = s.lastIndexOfChar ('.');
828
829 if (lastDot > jmax (0, len - 12))
830 {
831 s = s.substring (0, maxLength - (len - lastDot))
832 + s.substring (lastDot);
833 }
834 else
835 {
836 s = s.substring (0, maxLength);
837 }
838 }
839
840 return s;
841}
842
843//==============================================================================
844static int countNumberOfSeparators (String::CharPointerType s)
845{
846 int num = 0;
847
848 for (;;)
849 {
850 auto c = s.getAndAdvance();
851
852 if (c == 0)
853 break;
854
855 if (c == File::getSeparatorChar())
856 ++num;
857 }
858
859 return num;
860}
861
863{
864 if (dir == *this)
865 return ".";
866
867 auto thisPath = fullPath;
868
869 while (thisPath.endsWithChar (getSeparatorChar()))
870 thisPath = thisPath.dropLastCharacters (1);
871
873 : dir.fullPath);
874
875 int commonBitLength = 0;
876 auto thisPathAfterCommon = thisPath.getCharPointer();
877 auto dirPathAfterCommon = dirPath.getCharPointer();
878
879 {
880 auto thisPathIter = thisPath.getCharPointer();
881 auto dirPathIter = dirPath.getCharPointer();
882
883 for (int i = 0;;)
884 {
885 auto c1 = thisPathIter.getAndAdvance();
886 auto c2 = dirPathIter.getAndAdvance();
887
888 #if NAMES_ARE_CASE_SENSITIVE
889 if (c1 != c2
890 #else
892 #endif
893 || c1 == 0)
894 break;
895
896 ++i;
897
898 if (c1 == getSeparatorChar())
899 {
900 thisPathAfterCommon = thisPathIter;
901 dirPathAfterCommon = dirPathIter;
902 commonBitLength = i;
903 }
904 }
905 }
906
907 // if the only common bit is the root, then just return the full path..
908 if (commonBitLength == 0 || (commonBitLength == 1 && thisPath[1] == getSeparatorChar()))
909 return fullPath;
910
911 auto numUpDirectoriesNeeded = countNumberOfSeparators (dirPathAfterCommon);
912
913 if (numUpDirectoriesNeeded == 0)
914 return thisPathAfterCommon;
915
916 #if JUCE_WINDOWS
917 auto s = String::repeatedString ("..\\", numUpDirectoriesNeeded);
918 #else
919 auto s = String::repeatedString ("../", numUpDirectoriesNeeded);
920 #endif
921 s.appendCharPointer (thisPathAfterCommon);
922 return s;
923}
924
925//==============================================================================
927{
928 auto tempFile = getSpecialLocation (tempDirectory)
930 .withFileExtension (fileNameEnding);
931
932 if (tempFile.exists())
933 return createTempFile (fileNameEnding);
934
935 return tempFile;
936}
937
938bool File::createSymbolicLink (const File& linkFileToCreate,
939 const String& nativePathOfTarget,
940 bool overwriteExisting)
941{
942 if (linkFileToCreate.exists())
943 {
944 if (! linkFileToCreate.isSymbolicLink())
945 {
946 // user has specified an existing file / directory as the link
947 // this is bad! the user could end up unintentionally destroying data
948 jassertfalse;
949 return false;
950 }
951
952 if (overwriteExisting)
953 linkFileToCreate.deleteFile();
954 }
955
956 #if JUCE_MAC || JUCE_LINUX
957 // one common reason for getting an error here is that the file already exists
958 if (symlink (nativePathOfTarget.toRawUTF8(), linkFileToCreate.getFullPathName().toRawUTF8()) == -1)
959 {
960 jassertfalse;
961 return false;
962 }
963
964 return true;
965 #elif JUCE_MSVC
966 File targetFile (linkFileToCreate.getSiblingFile (nativePathOfTarget));
967
968 return CreateSymbolicLink (linkFileToCreate.getFullPathName().toWideCharPointer(),
969 nativePathOfTarget.toWideCharPointer(),
970 targetFile.isDirectory() ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) != FALSE;
971 #else
972 ignoreUnused (nativePathOfTarget);
973 jassertfalse; // symbolic links not supported on this platform!
974 return false;
975 #endif
976}
977
978bool File::createSymbolicLink (const File& linkFileToCreate, bool overwriteExisting) const
979{
980 return createSymbolicLink (linkFileToCreate, getFullPathName(), overwriteExisting);
981}
982
983#if ! JUCE_WINDOWS
985{
986 if (isSymbolicLink())
988
989 return *this;
990}
991#endif
992
993//==============================================================================
995 : range (0, file.getSize())
996{
997 openInternal (file, mode, exclusive);
998}
999
1000MemoryMappedFile::MemoryMappedFile (const File& file, const Range<int64>& fileRange, AccessMode mode, bool exclusive)
1001 : range (fileRange.getIntersectionWith (Range<int64> (0, file.getSize())))
1002{
1003 openInternal (file, mode, exclusive);
1004}
1005
1006
1007//==============================================================================
1008#if JUCE_UNIT_TESTS
1009
1010class FileTests : public UnitTest
1011{
1012public:
1013 FileTests() : UnitTest ("Files", "Files") {}
1014
1015 void runTest() override
1016 {
1017 beginTest ("Reading");
1018
1019 const File home (File::getSpecialLocation (File::userHomeDirectory));
1020 const File temp (File::getSpecialLocation (File::tempDirectory));
1021
1022 expect (! File().exists());
1023 expect (! File().existsAsFile());
1024 expect (! File().isDirectory());
1025 #if ! JUCE_WINDOWS
1026 expect (File("/").isDirectory());
1027 #endif
1028 expect (home.isDirectory());
1029 expect (home.exists());
1030 expect (! home.existsAsFile());
1031 expect (File::getSpecialLocation (File::userDocumentsDirectory).isDirectory());
1032 expect (File::getSpecialLocation (File::userApplicationDataDirectory).isDirectory());
1033 expect (File::getSpecialLocation (File::currentExecutableFile).exists());
1034 expect (File::getSpecialLocation (File::currentApplicationFile).exists());
1035 expect (File::getSpecialLocation (File::invokedExecutableFile).exists());
1036 expect (home.getVolumeTotalSize() > 1024 * 1024);
1037 expect (home.getBytesFreeOnVolume() > 0);
1038 expect (! home.isHidden());
1039 expect (home.isOnHardDisk());
1040 expect (! home.isOnCDRomDrive());
1041 expect (File::getCurrentWorkingDirectory().exists());
1042 expect (home.setAsCurrentWorkingDirectory());
1043 expect (File::getCurrentWorkingDirectory() == home);
1044
1045 {
1046 Array<File> roots;
1047 File::findFileSystemRoots (roots);
1048 expect (roots.size() > 0);
1049
1050 int numRootsExisting = 0;
1051 for (int i = 0; i < roots.size(); ++i)
1052 if (roots[i].exists())
1053 ++numRootsExisting;
1054
1055 // (on windows, some of the drives may not contain media, so as long as at least one is ok..)
1056 expect (numRootsExisting > 0);
1057 }
1058
1059 beginTest ("Writing");
1060
1061 File demoFolder (temp.getChildFile ("JUCE UnitTests Temp Folder.folder"));
1062 expect (demoFolder.deleteRecursively());
1063 expect (demoFolder.createDirectory());
1064 expect (demoFolder.isDirectory());
1065 expect (demoFolder.getParentDirectory() == temp);
1066 expect (temp.isDirectory());
1067 expect (temp.findChildFiles (File::findFilesAndDirectories, false, "*").contains (demoFolder));
1068 expect (temp.findChildFiles (File::findDirectories, true, "*.folder").contains (demoFolder));
1069
1070 File tempFile (demoFolder.getNonexistentChildFile ("test", ".txt", false));
1071
1072 expect (tempFile.getFileExtension() == ".txt");
1073 expect (tempFile.hasFileExtension (".txt"));
1074 expect (tempFile.hasFileExtension ("txt"));
1075 expect (tempFile.withFileExtension ("xyz").hasFileExtension (".xyz"));
1076 expect (tempFile.withFileExtension ("xyz").hasFileExtension ("abc;xyz;foo"));
1077 expect (tempFile.withFileExtension ("xyz").hasFileExtension ("xyz;foo"));
1078 expect (! tempFile.withFileExtension ("h").hasFileExtension ("bar;foo;xx"));
1079 expect (tempFile.getSiblingFile ("foo").isAChildOf (temp));
1080 expect (tempFile.hasWriteAccess());
1081
1082 expect (home.getChildFile (".") == home);
1083 expect (home.getChildFile ("..") == home.getParentDirectory());
1084 expect (home.getChildFile (".xyz").getFileName() == ".xyz");
1085 expect (home.getChildFile ("..xyz").getFileName() == "..xyz");
1086 expect (home.getChildFile ("...xyz").getFileName() == "...xyz");
1087 expect (home.getChildFile ("./xyz") == home.getChildFile ("xyz"));
1088 expect (home.getChildFile ("././xyz") == home.getChildFile ("xyz"));
1089 expect (home.getChildFile ("../xyz") == home.getParentDirectory().getChildFile ("xyz"));
1090 expect (home.getChildFile (".././xyz") == home.getParentDirectory().getChildFile ("xyz"));
1091 expect (home.getChildFile (".././xyz/./abc") == home.getParentDirectory().getChildFile ("xyz/abc"));
1092 expect (home.getChildFile ("./../xyz") == home.getParentDirectory().getChildFile ("xyz"));
1093 expect (home.getChildFile ("a1/a2/a3/./../../a4") == home.getChildFile ("a1/a4"));
1094
1095 {
1096 FileOutputStream fo (tempFile);
1097 fo.write ("0123456789", 10);
1098 }
1099
1100 expect (tempFile.exists());
1101 expect (tempFile.getSize() == 10);
1102 expect (std::abs ((int) (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000);
1103 expectEquals (tempFile.loadFileAsString(), String ("0123456789"));
1104 expect (! demoFolder.containsSubDirectories());
1105
1106 expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() + File::getSeparatorString() + tempFile.getFileName());
1107 expectEquals (demoFolder.getParentDirectory().getRelativePathFrom (tempFile), ".." + File::getSeparatorString() + ".." + File::getSeparatorString() + demoFolder.getParentDirectory().getFileName());
1108
1109 expect (demoFolder.getNumberOfChildFiles (File::findFiles) == 1);
1110 expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 1);
1111 expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 0);
1112 demoFolder.getNonexistentChildFile ("tempFolder", "", false).createDirectory();
1113 expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 1);
1114 expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 2);
1115 expect (demoFolder.containsSubDirectories());
1116
1117 expect (tempFile.hasWriteAccess());
1118 tempFile.setReadOnly (true);
1119 expect (! tempFile.hasWriteAccess());
1120 tempFile.setReadOnly (false);
1121 expect (tempFile.hasWriteAccess());
1122
1123 Time t (Time::getCurrentTime());
1124 tempFile.setLastModificationTime (t);
1125 Time t2 = tempFile.getLastModificationTime();
1126 expect (std::abs ((int) (t2.toMilliseconds() - t.toMilliseconds())) <= 1000);
1127
1128 {
1129 MemoryBlock mb;
1130 tempFile.loadFileAsData (mb);
1131 expect (mb.getSize() == 10);
1132 expect (mb[0] == '0');
1133 }
1134
1135 {
1136 expect (tempFile.getSize() == 10);
1137 FileOutputStream fo (tempFile);
1138 expect (fo.openedOk());
1139
1140 expect (fo.setPosition (7));
1141 expect (fo.truncate().wasOk());
1142 expect (tempFile.getSize() == 7);
1143 fo.write ("789", 3);
1144 fo.flush();
1145 expect (tempFile.getSize() == 10);
1146 }
1147
1148 beginTest ("Memory-mapped files");
1149
1150 {
1151 MemoryMappedFile mmf (tempFile, MemoryMappedFile::readOnly);
1152 expect (mmf.getSize() == 10);
1153 expect (mmf.getData() != nullptr);
1154 expect (memcmp (mmf.getData(), "0123456789", 10) == 0);
1155 }
1156
1157 {
1158 const File tempFile2 (tempFile.getNonexistentSibling (false));
1159 expect (tempFile2.create());
1160 expect (tempFile2.appendData ("xxxxxxxxxx", 10));
1161
1162 {
1163 MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
1164 expect (mmf.getSize() == 10);
1165 expect (mmf.getData() != nullptr);
1166 memcpy (mmf.getData(), "abcdefghij", 10);
1167 }
1168
1169 {
1170 MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
1171 expect (mmf.getSize() == 10);
1172 expect (mmf.getData() != nullptr);
1173 expect (memcmp (mmf.getData(), "abcdefghij", 10) == 0);
1174 }
1175
1176 expect (tempFile2.deleteFile());
1177 }
1178
1179 beginTest ("More writing");
1180
1181 expect (tempFile.appendData ("abcdefghij", 10));
1182 expect (tempFile.getSize() == 20);
1183 expect (tempFile.replaceWithData ("abcdefghij", 10));
1184 expect (tempFile.getSize() == 10);
1185
1186 File tempFile2 (tempFile.getNonexistentSibling (false));
1187 expect (tempFile.copyFileTo (tempFile2));
1188 expect (tempFile2.exists());
1189 expect (tempFile2.hasIdenticalContentTo (tempFile));
1190 expect (tempFile.deleteFile());
1191 expect (! tempFile.exists());
1192 expect (tempFile2.moveFileTo (tempFile));
1193 expect (tempFile.exists());
1194 expect (! tempFile2.exists());
1195
1196 expect (demoFolder.deleteRecursively());
1197 expect (! demoFolder.exists());
1198 }
1199};
1200
1201static FileTests fileUnitTests;
1202
1203#endif
1204
1205} // namespace juce
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:60
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition juce_Array.h:375
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
juce_wchar getAndAdvance() noexcept
Returns the character that this pointer is currently pointing to, and then advances the pointer to po...
int indexOf(const CharPointer stringToFind) const noexcept
Returns the character index of a substring, or -1 if it isn't found.
static juce_wchar toLowerCase(juce_wchar character) noexcept
Converts a character to lower-case.
static bool isDigit(char character) noexcept
Checks whether a character is a digit.
Searches through the files in a directory, returning each file that is found.
bool next()
Moves the iterator along to the next file.
An input stream that reads from a local file.
int read(void *, int) override
Reads some data from the stream into a memory buffer.
bool openedOk() const noexcept
Returns true if the stream opened without problems.
An output stream that writes into a local file.
const Result & getStatus() const noexcept
Returns the status of the file stream.
bool write(const void *, size_t) override
Writes a block of data to the stream.
bool failedToOpen() const noexcept
Returns true if the stream couldn't be opened for some reason.
bool openedOk() const noexcept
Returns true if the stream opened without problems.
Represents a local file or directory.
Definition juce_File.h:45
bool replaceWithText(const String &textToWrite, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\r\n") const
Replaces this file's contents with a given text string.
bool isSymbolicLink() const
Returns true if this file is a link or alias that can be followed using getLinkedTarget().
int getNumberOfChildFiles(int whatToLookFor, const String &wildCardPattern="*") const
Searches inside a directory and counts how many files match a wildcard pattern.
bool moveFileTo(const File &targetLocation) const
Moves or renames a file.
bool operator==(const File &) const
Compares the pathnames for two files.
int64 hashCode64() const
Returns a 64-bit hash-code that identifies this file.
bool containsSubDirectories() const
Returns true if this file is a directory that contains one or more subdirectories.
bool isDirectory() const
Checks whether the file is a directory that exists.
bool hasIdenticalContentTo(const File &other) const
Attempts to scan the contents of this file and compare it to another file, returning true if this is ...
FileOutputStream * createOutputStream(size_t bufferSize=0x8000) const
Creates a stream to write to this file.
static String createLegalPathName(const String &pathNameToFix)
Returns a version of a path with any illegal characters removed.
static String addTrailingSeparator(const String &path)
Adds a separator character to the end of a path if it doesn't already have one.
String getFileExtension() const
Returns the file's extension.
Time getLastModificationTime() const
Returns the last modification time of this file.
bool existsAsFile() const
Checks whether the file exists and is a file rather than a directory.
bool copyFileTo(const File &targetLocation) const
Copies a file.
int64 getSize() const
Returns the size of the file in bytes.
bool deleteRecursively(bool followSymlinks=false) const
Deletes a file or directory and all its subdirectories.
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
Finds the location of a special type of file or directory, such as a home folder or documents folder.
const String & getFullPathName() const noexcept
Returns the complete, absolute path of this file.
Definition juce_File.h:153
String getFileName() const
Returns the last section of the pathname.
bool replaceWithData(const void *dataToWrite, size_t numberOfBytes) const
Replaces this file's contents with a given block of data.
bool setLastAccessTime(Time newTime) const
Changes the last-access time for this file.
File getChildFile(StringRef relativeOrAbsolutePath) const
Returns a file that represents a relative (or absolute) sub-path of the current one.
void readLines(StringArray &destLines) const
Reads the contents of this file as text and splits it into lines, which are appended to the given Str...
static bool isAbsolutePath(StringRef path)
Returns true if the string seems to be a fully-specified absolute path.
File getSiblingFile(StringRef siblingFileName) const
Returns a file which is in the same directory as this one.
bool createSymbolicLink(const File &linkFileToCreate, bool overwriteExisting) const
Tries to create a symbolic link and returns a boolean to indicate success.
String getFileNameWithoutExtension() const
Returns the last part of the filename, without its file extension.
Array< File > findChildFiles(int whatToLookFor, bool searchRecursively, const String &wildCardPattern="*") const
Searches this directory for files matching a wildcard pattern.
File getNonexistentSibling(bool putNumbersInBrackets=true) const
Chooses a filename for a sibling file to this one that doesn't already exist.
@ tempDirectory
The folder that should be used for temporary files.
Definition juce_File.h:886
@ userHomeDirectory
The user's home folder.
Definition juce_File.h:836
String getRelativePathFrom(const File &directoryToBeRelativeTo) const
Creates a relative path that refers to a file relatively to a given directory.
bool appendText(const String &textToAppend, bool asUnicode=false, bool writeUnicodeHeaderBytes=false, const char *lineEndings="\r\n") const
Appends a string to the end of the file.
int hashCode() const
Returns a 32-bit hash-code that identifies this file.
Result create() const
Creates an empty file if it doesn't already exist.
@ findDirectories
Use this flag to indicate that you want to find directories.
Definition juce_File.h:553
@ findFilesAndDirectories
Use this flag to indicate that you want to find both files and directories.
Definition juce_File.h:555
@ findFiles
Use this flag to indicate that you want to find files.
Definition juce_File.h:554
File getNonexistentChildFile(const String &prefix, const String &suffix, bool putNumbersInBrackets=true) const
Chooses a filename relative to this one that doesn't already exist.
bool operator!=(const File &) const
Compares the pathnames for two files.
bool setCreationTime(Time newTime) const
Changes the creation date for this file.
static String descriptionOfSizeInBytes(int64 bytes)
Utility function to convert a file size in bytes to a neat string description.
bool setReadOnly(bool shouldBeReadOnly, bool applyRecursively=false) const
Changes the write-permission of a file or directory.
static File createTempFile(StringRef fileNameEnding)
Returns a temporary file in the system's temp directory.
static juce_wchar getSeparatorChar()
The system-specific file separator character.
static bool areFileNamesCaseSensitive()
Indicates whether filenames are case-sensitive on the current operating system.
bool isRoot() const
Checks whether the path of this file represents the root of a file system, irrespective of its existe...
String loadFileAsString() const
Reads a file into memory as a string.
FileInputStream * createInputStream() const
Creates a stream to read from this file.
bool operator>(const File &) const
Compares the pathnames for two files.
File getLinkedTarget() const
If this file is a link or alias, this returns the file that it points to.
File getParentDirectory() const
Returns the directory that contains this file or directory.
bool appendData(const void *dataToAppend, size_t numberOfBytes) const
Appends a block of binary data to the end of the file.
bool operator<(const File &) const
Compares the pathnames for two files.
Time getCreationTime() const
Returns the time that this file was created.
bool setExecutePermission(bool shouldBeExecutable) const
Changes the execute-permissions of a file.
File withFileExtension(StringRef newExtension) const
Returns a version of this file with a different file extension.
static String createLegalFileName(const String &fileNameToFix)
Returns a version of a filename with any illegal characters removed.
File()=default
Creates an (invalid) file object.
bool deleteFile() const
Deletes a file.
bool replaceFileIn(const File &targetLocation) const
Replaces a file.
bool isAChildOf(const File &potentialParentDirectory) const
Checks whether a file is somewhere inside a directory.
static File createFileWithoutCheckingPath(const String &absolutePath) noexcept
Creates a file that simply contains this string, without doing the sanity-checking that the normal co...
Definition juce_File.cpp:31
bool startAsProcess(const String &parameters=String()) const
Launches the file as a process.
String getNativeLinkedTarget() const
This returns the native path that the symbolic link points to.
bool hasFileExtension(StringRef extensionToTest) const
Checks whether the file has a given extension.
bool exists() const
Checks whether the file actually exists.
bool copyDirectoryTo(const File &newDirectory) const
Copies a directory.
bool loadFileAsData(MemoryBlock &result) const
Loads a file's contents into memory as a block of binary data.
bool setLastModificationTime(Time newTime) const
Changes the modification time for this file.
Time getLastAccessTime() const
Returns the last time this file was accessed.
Result createDirectory() const
Creates a new directory for this filename.
static File getCurrentWorkingDirectory()
Returns the current working directory.
static StringRef getSeparatorString()
The system-specific file separator character, as a string.
File & operator=(const String &newAbsolutePath)
Sets the file based on an absolute pathname.
Definition juce_File.cpp:43
Very simple container class to hold a pointer to some data on the heap.
virtual size_t readIntoMemoryBlock(MemoryBlock &destBlock, ssize_t maxNumBytesToRead=-1)
Reads from the stream and appends the data to a MemoryBlock.
virtual String readEntireStreamAsString()
Tries to read the whole stream and turn it into a string.
static void JUCE_CALLTYPE writeToLog(const String &message)
Writes a string to the current logger.
A class to hold a resizable block of raw data.
MemoryMappedFile(const File &file, AccessMode mode, bool exclusive=false)
Opens a file and maps it to an area of virtual memory.
AccessMode
The read/write flags used when opening a memory mapped file.
virtual bool writeText(const String &text, bool asUTF16, bool writeUTF16ByteOrderMark, const char *lineEndings)
Writes a string of text to the stream.
static bool JUCE_CALLTYPE openDocument(const String &documentURL, const String &parameters)
Tries to launch the OS's default reader application for a given file or URL.
static Random & getSystemRandom() noexcept
The overhead of creating a new Random object is fairly small, but if you want to avoid it,...
A general-purpose range object, that simply represents any linear range with a start and end point.
Definition juce_Range.h:44
Represents the 'success' or 'failure' of an operation, and holds an associated error message to descr...
Definition juce_Result.h:61
static Result fail(const String &errorMessage) noexcept
Creates a 'failure' result.
static Result ok() noexcept
Creates and returns a 'successful' result.
Definition juce_Result.h:65
A special array for holding a list of strings.
int addLines(StringRef stringToBreakUp)
Breaks up a string into lines and adds them to this array.
A simple class for holding temporary references to a string literal or String.
bool isNotEmpty() const noexcept
Returns true if the string is not empty.
int length() const noexcept
Returns the number of characters in the string.
String::CharPointerType text
The text that is referenced.
bool isEmpty() const noexcept
Returns true if the string is empty.
The JUCE String class!
Definition juce_String.h:43
CharPointerType getCharPointer() const noexcept
Returns the character pointer currently being used to store this string.
static String repeatedString(StringRef stringToRepeat, int numberOfTimesToRepeat)
Creates a string which is a version of a string repeated and joined together.
int indexOfChar(juce_wchar characterToLookFor) const noexcept
Searches for a character inside this string.
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Returns the start of this string, up to the first occurrence of a substring.
int length() const noexcept
Returns the number of characters in the string.
bool endsWithChar(juce_wchar character) const noexcept
Tests whether the string ends with a particular character.
bool isEmpty() const noexcept
Returns true if the string contains no characters.
const char * toRawUTF8() const
Returns a pointer to a UTF-8 version of this string.
int64 hashCode64() const noexcept
Generates a probably-unique 64-bit hashcode from this string.
bool containsChar(juce_wchar character) const noexcept
Tests whether the string contains a particular character.
String removeCharacters(StringRef charactersToRemove) const
Returns a version of this string with a set of characters removed.
bool endsWithIgnoreCase(StringRef text) const noexcept
Tests whether the string ends with another string.
String dropLastCharacters(int numberToDrop) const
Returns a version of this string with a number of characters removed from the end.
String trimEnd() const
Returns a copy of this string with any whitespace characters removed from the end.
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
int lastIndexOfChar(juce_wchar character) const noexcept
Searches for a character inside this string (working backwards from the end of the string).
const wchar_t * toWideCharPointer() const
Returns a pointer to a wchar_t version of this string.
String trimCharactersAtEnd(StringRef charactersToTrim) const
Returns a copy of this string, having removed a specified set of characters from its end.
String replaceCharacter(juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const
Returns a string with all occurrences of a character replaced with a different one.
String substring(int startIndex, int endIndex) const
Returns a subsection of the string.
int hashCode() const noexcept
Generates a probably-unique 32-bit hashcode from this string.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from a given substring.
Manages a temporary file, which will be deleted when this object is deleted.
@ useHiddenFile
Indicates that the temporary file should be hidden - i.e.
bool overwriteTargetFileWithTemporary() const
Tries to move the temporary file to overwrite the target file that was specified in the constructor.
const File & getFile() const noexcept
Returns the temporary file.
Holds an absolute date and time.
Definition juce_Time.h:41
int64 toMilliseconds() const noexcept
Returns the time as a number of milliseconds.
Definition juce_Time.h:102
This is a base class for classes that perform a unit test.