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
27 : fullPath (parseAbsolutePath (fullPathName))
28{
29}
30
32{
33 File f;
34 f.fullPath = path;
35 return f;
36}
37
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
56 : fullPath (std::move (other.fullPath))
57{
58}
59
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
134 path = File::getCurrentWorkingDirectory().getFullPathName().substring (0, 2) + path;
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
148 return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
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"
165 path = File::getSpecialLocation (File::userHomeDirectory).getFullPathName()
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
197 return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
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//==============================================================================
243 const bool applyRecursively) const
244{
245 bool worked = true;
246
248 for (auto& f : findChildFiles (File::findFilesAndDirectories, false))
249 worked = f.setReadOnly (shouldBeReadOnly, true) && worked;
250
251 return setFileReadOnlyInternal (shouldBeReadOnly) && worked;
252}
253
255{
256 return setFileExecutableInternal (shouldBeExecutable);
257}
258
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
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
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
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
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;
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
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
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
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//==============================================================================
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
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{
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
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
654 return fullPath.substring (indexOfDot);
655
656 return {};
657}
658
660{
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
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
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
872 auto dirPath = addTrailingSeparator (dir.existsAsFile() ? dir.getParentDirectory().getFullPathName()
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 {
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
918 #else
920 #endif
921 s.appendCharPointer (thisPathAfterCommon);
922 return s;
923}
924
925//==============================================================================
927{
929 .getChildFile ("temp_" + String::toHexString (Random::getSystemRandom().nextInt()))
930 .withFileExtension (fileNameEnding);
931
932 if (tempFile.exists())
934
935 return tempFile;
936}
937
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
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
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
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
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());
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());
1044
1045 {
1048 expect (roots.size() > 0);
1049
1050 int numRootsExisting = 0;
1051 for (int i = 0; i < roots.size(); ++i)
1052 if (roots[i].exists())
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
bool isEmpty() const noexcept
Returns true if the array is empty, false otherwise.
Definition juce_Array.h:226
void removeRange(int startIndex, int numberToRemove)
Removes a range of elements from the array.
Definition juce_Array.h:873
Array()=default
Creates an empty array.
int indexOf(ParameterType elementToLookFor) const
Finds the index of the first element which matches the value passed in.
Definition juce_Array.h:339
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 ...
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.
An input stream that reads from a local file.
An output stream that writes into a local file.
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.
static void findFileSystemRoots(Array< File > &results)
Creates a set of files to represent each file root.
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
@ userDocumentsDirectory
The user's default documents folder.
Definition juce_File.h:842
@ currentApplicationFile
Returns this application's location.
Definition juce_File.h:909
@ invokedExecutableFile
Returns the file that was invoked to launch this executable.
Definition juce_File.h:916
@ userApplicationDataDirectory
The folder in which applications store their persistent user-specific settings.
Definition juce_File.h:862
@ currentExecutableFile
Returns this application's executable file.
Definition juce_File.h:899
@ 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
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.
@ readWrite
Indicates that the memory can be read and written to - changes that are made will be flushed back to ...
@ readOnly
Indicates that the memory can only be read.
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.
A simple class for holding temporary references to a string literal or String.
String::CharPointerType text
The text that is referenced.
The JUCE String class!
Definition juce_String.h:43
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.
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.
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.
bool endsWithIgnoreCase(StringRef text) const noexcept
Tests whether the string ends with another string.
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).
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.
Manages a temporary file, which will be deleted when this object is deleted.
@ useHiddenFile
Indicates that the temporary file should be hidden - i.e.
Holds an absolute date and time.
Definition juce_Time.h:41
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
This is a base class for classes that perform a unit test.