Add remaining files
[juce-lv2.git] / juce / source / src / io / files / juce_File.cpp
blob7a72da6fa9a650a1adf49060dce5cf92bbf51878
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
28 #if ! JUCE_WINDOWS
29 #include <pwd.h>
30 #endif
32 BEGIN_JUCE_NAMESPACE
34 #include "juce_File.h"
35 #include "juce_FileInputStream.h"
36 #include "juce_FileOutputStream.h"
37 #include "juce_DirectoryIterator.h"
38 #include "juce_TemporaryFile.h"
39 #include "../../core/juce_SystemStats.h"
40 #include "../../maths/juce_Random.h"
41 #include "../../core/juce_PlatformUtilities.h"
42 #include "../../memory/juce_ScopedPointer.h"
45 //==============================================================================
46 File::File (const String& fullPathName)
47 : fullPath (parseAbsolutePath (fullPathName))
51 File::File (const String& path, int)
52 : fullPath (path)
56 File File::createFileWithoutCheckingPath (const String& path)
58 return File (path, 0);
61 File::File (const File& other)
62 : fullPath (other.fullPath)
66 File& File::operator= (const String& newPath)
68 fullPath = parseAbsolutePath (newPath);
69 return *this;
72 File& File::operator= (const File& other)
74 fullPath = other.fullPath;
75 return *this;
78 const File File::nonexistent;
81 //==============================================================================
82 String File::parseAbsolutePath (const String& p)
84 if (p.isEmpty())
85 return String::empty;
87 #if JUCE_WINDOWS
88 // Windows..
89 String path (p.replaceCharacter ('/', '\\'));
91 if (path.startsWithChar (File::separator))
93 if (path[1] != File::separator)
95 /* When you supply a raw string to the File object constructor, it must be an absolute path.
96 If you're trying to parse a string that may be either a relative path or an absolute path,
97 you MUST provide a context against which the partial path can be evaluated - you can do
98 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
99 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
100 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
102 jassertfalse;
104 path = File::getCurrentWorkingDirectory().getFullPathName().substring (0, 2) + path;
107 else if (! path.containsChar (':'))
109 /* When you supply a raw string to the File object constructor, it must be an absolute path.
110 If you're trying to parse a string that may be either a relative path or an absolute path,
111 you MUST provide a context against which the partial path can be evaluated - you can do
112 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
113 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
114 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
116 jassertfalse;
118 return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
120 #else
121 // Mac or Linux..
123 // Yes, I know it's legal for a unix pathname to contain a backslash, but this assertion is here
124 // to catch anyone who's trying to run code that was written on Windows with hard-coded path names.
125 // If that's why you've ended up here, use File::getChildFile() to build your paths instead.
126 jassert ((! p.containsChar ('\\')) || (p.indexOfChar ('/') >= 0 && p.indexOfChar ('/') < p.indexOfChar ('\\')));
128 String path (p);
130 if (path.startsWithChar ('~'))
132 if (path[1] == File::separator || path[1] == 0)
134 // expand a name of the form "~/abc"
135 path = File::getSpecialLocation (File::userHomeDirectory).getFullPathName()
136 + path.substring (1);
138 else
140 // expand a name of type "~dave/abc"
141 const String userName (path.substring (1).upToFirstOccurrenceOf ("/", false, false));
143 struct passwd* const pw = getpwnam (userName.toUTF8());
144 if (pw != nullptr)
145 path = addTrailingSeparator (pw->pw_dir) + path.fromFirstOccurrenceOf ("/", false, false);
148 else if (! path.startsWithChar (File::separator))
150 /* When you supply a raw string to the File object constructor, it must be an absolute path.
151 If you're trying to parse a string that may be either a relative path or an absolute path,
152 you MUST provide a context against which the partial path can be evaluated - you can do
153 this by simply using File::getChildFile() instead of the File constructor. E.g. saying
154 "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute
155 path if that's what was supplied, or would evaluate a partial path relative to the CWD.
157 jassert (path.startsWith ("./") || path.startsWith ("../")); // (assume that a path "./xyz" is deliberately intended to be relative to the CWD)
159 return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName();
161 #endif
163 while (path.endsWithChar (separator) && path != separatorString) // careful not to turn a single "/" into an empty string.
164 path = path.dropLastCharacters (1);
166 return path;
169 String File::addTrailingSeparator (const String& path)
171 return path.endsWithChar (File::separator) ? path
172 : path + File::separator;
175 //==============================================================================
176 #if JUCE_LINUX
177 #define NAMES_ARE_CASE_SENSITIVE 1
178 #endif
180 bool File::areFileNamesCaseSensitive()
182 #if NAMES_ARE_CASE_SENSITIVE
183 return true;
184 #else
185 return false;
186 #endif
189 bool File::operator== (const File& other) const
191 #if NAMES_ARE_CASE_SENSITIVE
192 return fullPath == other.fullPath;
193 #else
194 return fullPath.equalsIgnoreCase (other.fullPath);
195 #endif
198 bool File::operator!= (const File& other) const
200 return ! operator== (other);
203 bool File::operator< (const File& other) const
205 #if NAMES_ARE_CASE_SENSITIVE
206 return fullPath < other.fullPath;
207 #else
208 return fullPath.compareIgnoreCase (other.fullPath) < 0;
209 #endif
212 bool File::operator> (const File& other) const
214 #if NAMES_ARE_CASE_SENSITIVE
215 return fullPath > other.fullPath;
216 #else
217 return fullPath.compareIgnoreCase (other.fullPath) > 0;
218 #endif
221 //==============================================================================
222 bool File::setReadOnly (const bool shouldBeReadOnly,
223 const bool applyRecursively) const
225 bool worked = true;
227 if (applyRecursively && isDirectory())
229 Array <File> subFiles;
230 findChildFiles (subFiles, File::findFilesAndDirectories, false);
232 for (int i = subFiles.size(); --i >= 0;)
233 worked = subFiles.getReference(i).setReadOnly (shouldBeReadOnly, true) && worked;
236 return setFileReadOnlyInternal (shouldBeReadOnly) && worked;
239 bool File::deleteRecursively() const
241 bool worked = true;
243 if (isDirectory())
245 Array<File> subFiles;
246 findChildFiles (subFiles, File::findFilesAndDirectories, false);
248 for (int i = subFiles.size(); --i >= 0;)
249 worked = subFiles.getReference(i).deleteRecursively() && worked;
252 return deleteFile() && worked;
255 bool File::moveFileTo (const File& newFile) const
257 if (newFile.fullPath == fullPath)
258 return true;
260 #if ! NAMES_ARE_CASE_SENSITIVE
261 if (*this != newFile)
262 #endif
263 if (! newFile.deleteFile())
264 return false;
266 return moveInternal (newFile);
269 bool File::copyFileTo (const File& newFile) const
271 return (*this == newFile)
272 || (exists() && newFile.deleteFile() && copyInternal (newFile));
275 bool File::copyDirectoryTo (const File& newDirectory) const
277 if (isDirectory() && newDirectory.createDirectory())
279 Array<File> subFiles;
280 findChildFiles (subFiles, File::findFiles, false);
282 int i;
283 for (i = 0; i < subFiles.size(); ++i)
284 if (! subFiles.getReference(i).copyFileTo (newDirectory.getChildFile (subFiles.getReference(i).getFileName())))
285 return false;
287 subFiles.clear();
288 findChildFiles (subFiles, File::findDirectories, false);
290 for (i = 0; i < subFiles.size(); ++i)
291 if (! subFiles.getReference(i).copyDirectoryTo (newDirectory.getChildFile (subFiles.getReference(i).getFileName())))
292 return false;
294 return true;
297 return false;
300 //==============================================================================
301 String File::getPathUpToLastSlash() const
303 const int lastSlash = fullPath.lastIndexOfChar (separator);
305 if (lastSlash > 0)
306 return fullPath.substring (0, lastSlash);
307 else if (lastSlash == 0)
308 return separatorString;
309 else
310 return fullPath;
313 File File::getParentDirectory() const
315 return File (getPathUpToLastSlash(), (int) 0);
318 //==============================================================================
319 String File::getFileName() const
321 return fullPath.substring (fullPath.lastIndexOfChar (separator) + 1);
324 int File::hashCode() const
326 return fullPath.hashCode();
329 int64 File::hashCode64() const
331 return fullPath.hashCode64();
334 String File::getFileNameWithoutExtension() const
336 const int lastSlash = fullPath.lastIndexOfChar (separator) + 1;
337 const int lastDot = fullPath.lastIndexOfChar ('.');
339 if (lastDot > lastSlash)
340 return fullPath.substring (lastSlash, lastDot);
341 else
342 return fullPath.substring (lastSlash);
345 bool File::isAChildOf (const File& potentialParent) const
347 if (potentialParent == File::nonexistent)
348 return false;
350 const String ourPath (getPathUpToLastSlash());
352 #if NAMES_ARE_CASE_SENSITIVE
353 if (potentialParent.fullPath == ourPath)
354 #else
355 if (potentialParent.fullPath.equalsIgnoreCase (ourPath))
356 #endif
358 return true;
360 else if (potentialParent.fullPath.length() >= ourPath.length())
362 return false;
364 else
366 return getParentDirectory().isAChildOf (potentialParent);
370 //==============================================================================
371 bool File::isAbsolutePath (const String& path)
373 return path.startsWithChar (separator)
374 #if JUCE_WINDOWS
375 || (path.isNotEmpty() && path[1] == ':');
376 #else
377 || path.startsWithChar ('~');
378 #endif
381 File File::getChildFile (String relativePath) const
383 if (isAbsolutePath (relativePath))
384 return File (relativePath);
386 String path (fullPath);
388 // It's relative, so remove any ../ or ./ bits at the start..
389 if (relativePath[0] == '.')
391 #if JUCE_WINDOWS
392 relativePath = relativePath.replaceCharacter ('/', '\\').trimStart();
393 #else
394 relativePath = relativePath.trimStart();
395 #endif
397 while (relativePath[0] == '.')
399 if (relativePath[1] == '.')
401 if (relativePath [2] == 0 || relativePath[2] == separator)
403 const int lastSlash = path.lastIndexOfChar (separator);
404 if (lastSlash >= 0)
405 path = path.substring (0, lastSlash);
407 relativePath = relativePath.substring (3);
409 else
411 break;
414 else if (relativePath[1] == separator)
416 relativePath = relativePath.substring (2);
418 else
420 break;
425 return File (addTrailingSeparator (path) + relativePath);
428 File File::getSiblingFile (const String& fileName) const
430 return getParentDirectory().getChildFile (fileName);
433 //==============================================================================
434 String File::descriptionOfSizeInBytes (const int64 bytes)
436 if (bytes == 1) return "1 byte";
437 else if (bytes < 1024) return String (bytes) + " bytes";
438 else if (bytes < 1024 * 1024) return String (bytes / 1024.0, 1) + " KB";
439 else if (bytes < 1024 * 1024 * 1024) return String (bytes / (1024.0 * 1024.0), 1) + " MB";
440 else return String (bytes / (1024.0 * 1024.0 * 1024.0), 1) + " GB";
443 //==============================================================================
444 Result File::create() const
446 if (exists())
447 return Result::ok();
449 const File parentDir (getParentDirectory());
451 if (parentDir == *this)
452 return Result::fail ("Cannot create parent directory");
454 Result r (parentDir.createDirectory());
456 if (r.wasOk())
458 FileOutputStream fo (*this, 8);
460 r = fo.getStatus();
463 return r;
466 Result File::createDirectory() const
468 if (isDirectory())
469 return Result::ok();
471 const File parentDir (getParentDirectory());
473 if (parentDir == *this)
474 return Result::fail ("Cannot create parent directory");
476 Result r (parentDir.createDirectory());
478 if (r.wasOk())
479 r = createDirectoryInternal (fullPath.trimCharactersAtEnd (separatorString));
481 return r;
484 //==============================================================================
485 Time File::getLastModificationTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (m); }
486 Time File::getLastAccessTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (a); }
487 Time File::getCreationTime() const { int64 m, a, c; getFileTimesInternal (m, a, c); return Time (c); }
489 bool File::setLastModificationTime (const Time& t) const { return setFileTimesInternal (t.toMilliseconds(), 0, 0); }
490 bool File::setLastAccessTime (const Time& t) const { return setFileTimesInternal (0, t.toMilliseconds(), 0); }
491 bool File::setCreationTime (const Time& t) const { return setFileTimesInternal (0, 0, t.toMilliseconds()); }
493 //==============================================================================
494 bool File::loadFileAsData (MemoryBlock& destBlock) const
496 if (! existsAsFile())
497 return false;
499 FileInputStream in (*this);
500 return getSize() == in.readIntoMemoryBlock (destBlock);
503 String File::loadFileAsString() const
505 if (! existsAsFile())
506 return String::empty;
508 FileInputStream in (*this);
509 return in.readEntireStreamAsString();
512 //==============================================================================
513 int File::findChildFiles (Array<File>& results,
514 const int whatToLookFor,
515 const bool searchRecursively,
516 const String& wildCardPattern) const
518 DirectoryIterator di (*this, searchRecursively, wildCardPattern, whatToLookFor);
520 int total = 0;
521 while (di.next())
523 results.add (di.getFile());
524 ++total;
527 return total;
530 int File::getNumberOfChildFiles (const int whatToLookFor, const String& wildCardPattern) const
532 DirectoryIterator di (*this, false, wildCardPattern, whatToLookFor);
534 int total = 0;
535 while (di.next())
536 ++total;
538 return total;
541 bool File::containsSubDirectories() const
543 if (isDirectory())
545 DirectoryIterator di (*this, false, "*", findDirectories);
546 return di.next();
549 return false;
552 //==============================================================================
553 File File::getNonexistentChildFile (const String& prefix_,
554 const String& suffix,
555 bool putNumbersInBrackets) const
557 File f (getChildFile (prefix_ + suffix));
559 if (f.exists())
561 int num = 2;
562 String prefix (prefix_);
564 // remove any bracketed numbers that may already be on the end..
565 if (prefix.trim().endsWithChar (')'))
567 putNumbersInBrackets = true;
569 const int openBracks = prefix.lastIndexOfChar ('(');
570 const int closeBracks = prefix.lastIndexOfChar (')');
572 if (openBracks > 0
573 && closeBracks > openBracks
574 && prefix.substring (openBracks + 1, closeBracks).containsOnly ("0123456789"))
576 num = prefix.substring (openBracks + 1, closeBracks).getIntValue() + 1;
577 prefix = prefix.substring (0, openBracks);
581 // also use brackets if it ends in a digit.
582 putNumbersInBrackets = putNumbersInBrackets
583 || CharacterFunctions::isDigit (prefix.getLastCharacter());
587 String newName (prefix);
589 if (putNumbersInBrackets)
590 newName << '(' << num++ << ')';
591 else
592 newName << num++;
594 f = getChildFile (newName + suffix);
596 } while (f.exists());
599 return f;
602 File File::getNonexistentSibling (const bool putNumbersInBrackets) const
604 if (exists())
605 return getParentDirectory()
606 .getNonexistentChildFile (getFileNameWithoutExtension(),
607 getFileExtension(),
608 putNumbersInBrackets);
609 return *this;
612 //==============================================================================
613 String File::getFileExtension() const
615 const int indexOfDot = fullPath.lastIndexOfChar ('.');
617 if (indexOfDot > fullPath.lastIndexOfChar (separator))
618 return fullPath.substring (indexOfDot);
620 return String::empty;
623 bool File::hasFileExtension (const String& possibleSuffix) const
625 if (possibleSuffix.isEmpty())
626 return fullPath.lastIndexOfChar ('.') <= fullPath.lastIndexOfChar (separator);
628 const int semicolon = possibleSuffix.indexOfChar (0, ';');
630 if (semicolon >= 0)
632 return hasFileExtension (possibleSuffix.substring (0, semicolon).trimEnd())
633 || hasFileExtension (possibleSuffix.substring (semicolon + 1).trimStart());
635 else
637 if (fullPath.endsWithIgnoreCase (possibleSuffix))
639 if (possibleSuffix.startsWithChar ('.'))
640 return true;
642 const int dotPos = fullPath.length() - possibleSuffix.length() - 1;
644 if (dotPos >= 0)
645 return fullPath [dotPos] == '.';
649 return false;
652 File File::withFileExtension (const String& newExtension) const
654 if (fullPath.isEmpty())
655 return File::nonexistent;
657 String filePart (getFileName());
659 int i = filePart.lastIndexOfChar ('.');
660 if (i >= 0)
661 filePart = filePart.substring (0, i);
663 if (newExtension.isNotEmpty() && ! newExtension.startsWithChar ('.'))
664 filePart << '.';
666 return getSiblingFile (filePart + newExtension);
669 //==============================================================================
670 bool File::startAsProcess (const String& parameters) const
672 return exists() && PlatformUtilities::openDocument (fullPath, parameters);
675 //==============================================================================
676 FileInputStream* File::createInputStream() const
678 if (existsAsFile())
679 return new FileInputStream (*this);
681 return nullptr;
684 FileOutputStream* File::createOutputStream (const int bufferSize) const
686 ScopedPointer <FileOutputStream> out (new FileOutputStream (*this, bufferSize));
688 if (out->failedToOpen())
689 return nullptr;
691 return out.release();
694 //==============================================================================
695 bool File::appendData (const void* const dataToAppend,
696 const int numberOfBytes) const
698 if (numberOfBytes > 0)
700 const ScopedPointer <FileOutputStream> out (createOutputStream());
702 if (out == 0)
703 return false;
705 out->write (dataToAppend, numberOfBytes);
708 return true;
711 bool File::replaceWithData (const void* const dataToWrite,
712 const int numberOfBytes) const
714 jassert (numberOfBytes >= 0); // a negative number of bytes??
716 if (numberOfBytes <= 0)
717 return deleteFile();
719 TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile);
720 tempFile.getFile().appendData (dataToWrite, numberOfBytes);
721 return tempFile.overwriteTargetFileWithTemporary();
724 bool File::appendText (const String& text,
725 const bool asUnicode,
726 const bool writeUnicodeHeaderBytes) const
728 const ScopedPointer <FileOutputStream> out (createOutputStream());
730 if (out != nullptr)
732 out->writeText (text, asUnicode, writeUnicodeHeaderBytes);
733 return true;
736 return false;
739 bool File::replaceWithText (const String& textToWrite,
740 const bool asUnicode,
741 const bool writeUnicodeHeaderBytes) const
743 TemporaryFile tempFile (*this, TemporaryFile::useHiddenFile);
744 tempFile.getFile().appendText (textToWrite, asUnicode, writeUnicodeHeaderBytes);
745 return tempFile.overwriteTargetFileWithTemporary();
748 bool File::hasIdenticalContentTo (const File& other) const
750 if (other == *this)
751 return true;
753 if (getSize() == other.getSize() && existsAsFile() && other.existsAsFile())
755 FileInputStream in1 (*this), in2 (other);
757 const int bufferSize = 4096;
758 HeapBlock <char> buffer1 (bufferSize), buffer2 (bufferSize);
760 for (;;)
762 const int num1 = in1.read (buffer1, bufferSize);
763 const int num2 = in2.read (buffer2, bufferSize);
765 if (num1 != num2)
766 break;
768 if (num1 <= 0)
769 return true;
771 if (memcmp (buffer1, buffer2, num1) != 0)
772 break;
776 return false;
779 //==============================================================================
780 String File::createLegalPathName (const String& original)
782 String s (original);
783 String start;
785 if (s[1] == ':')
787 start = s.substring (0, 2);
788 s = s.substring (2);
791 return start + s.removeCharacters ("\"#@,;:<>*^|?")
792 .substring (0, 1024);
795 String File::createLegalFileName (const String& original)
797 String s (original.removeCharacters ("\"#@,;:<>*^|?\\/"));
799 const int maxLength = 128; // only the length of the filename, not the whole path
800 const int len = s.length();
802 if (len > maxLength)
804 const int lastDot = s.lastIndexOfChar ('.');
806 if (lastDot > jmax (0, len - 12))
808 s = s.substring (0, maxLength - (len - lastDot))
809 + s.substring (lastDot);
811 else
813 s = s.substring (0, maxLength);
817 return s;
820 //==============================================================================
821 String File::getRelativePathFrom (const File& dir) const
823 String thisPath (fullPath);
825 while (thisPath.endsWithChar (separator))
826 thisPath = thisPath.dropLastCharacters (1);
828 String dirPath (addTrailingSeparator (dir.existsAsFile() ? dir.getParentDirectory().getFullPathName()
829 : dir.fullPath));
831 const int len = jmin (thisPath.length(), dirPath.length());
832 int commonBitLength = 0;
835 String::CharPointerType thisPathIter (thisPath.getCharPointer());
836 String::CharPointerType dirPathIter (dirPath.getCharPointer());
838 for (int i = 0; i < len; ++i)
840 const juce_wchar c1 = thisPathIter.getAndAdvance();
841 const juce_wchar c2 = dirPathIter.getAndAdvance();
843 #if NAMES_ARE_CASE_SENSITIVE
844 if (c1 != c2)
845 #else
846 if (c1 != c2 && CharacterFunctions::toLowerCase (c1) != CharacterFunctions::toLowerCase (c2))
847 #endif
848 break;
850 ++commonBitLength;
854 while (commonBitLength > 0 && thisPath [commonBitLength - 1] != File::separator)
855 --commonBitLength;
857 // if the only common bit is the root, then just return the full path..
858 if (commonBitLength <= 0
859 || (commonBitLength == 1 && thisPath [1] == File::separator))
860 return fullPath;
862 thisPath = thisPath.substring (commonBitLength);
863 dirPath = dirPath.substring (commonBitLength);
865 while (dirPath.isNotEmpty())
867 #if JUCE_WINDOWS
868 thisPath = "..\\" + thisPath;
869 #else
870 thisPath = "../" + thisPath;
871 #endif
873 const int sep = dirPath.indexOfChar (separator);
875 if (sep >= 0)
876 dirPath = dirPath.substring (sep + 1);
877 else
878 dirPath = String::empty;
881 return thisPath;
884 //==============================================================================
885 File File::createTempFile (const String& fileNameEnding)
887 const File tempFile (getSpecialLocation (tempDirectory)
888 .getChildFile ("temp_" + String (Random::getSystemRandom().nextInt()))
889 .withFileExtension (fileNameEnding));
891 if (tempFile.exists())
892 return createTempFile (fileNameEnding);
894 return tempFile;
898 //==============================================================================
899 #if JUCE_UNIT_TESTS
901 #include "../../utilities/juce_UnitTest.h"
902 #include "../../maths/juce_Random.h"
903 #include "juce_MemoryMappedFile.h"
906 class FileTests : public UnitTest
908 public:
909 FileTests() : UnitTest ("Files") {}
911 void runTest()
913 beginTest ("Reading");
915 const File home (File::getSpecialLocation (File::userHomeDirectory));
916 const File temp (File::getSpecialLocation (File::tempDirectory));
918 expect (! File::nonexistent.exists());
919 expect (home.isDirectory());
920 expect (home.exists());
921 expect (! home.existsAsFile());
922 expect (File::getSpecialLocation (File::userDocumentsDirectory).isDirectory());
923 expect (File::getSpecialLocation (File::userApplicationDataDirectory).isDirectory());
924 expect (File::getSpecialLocation (File::currentExecutableFile).exists());
925 expect (File::getSpecialLocation (File::currentApplicationFile).exists());
926 expect (File::getSpecialLocation (File::invokedExecutableFile).exists());
927 expect (home.getVolumeTotalSize() > 1024 * 1024);
928 expect (home.getBytesFreeOnVolume() > 0);
929 expect (! home.isHidden());
930 expect (home.isOnHardDisk());
931 expect (! home.isOnCDRomDrive());
932 expect (File::getCurrentWorkingDirectory().exists());
933 expect (home.setAsCurrentWorkingDirectory());
934 expect (File::getCurrentWorkingDirectory() == home);
937 Array<File> roots;
938 File::findFileSystemRoots (roots);
939 expect (roots.size() > 0);
941 int numRootsExisting = 0;
942 for (int i = 0; i < roots.size(); ++i)
943 if (roots[i].exists())
944 ++numRootsExisting;
946 // (on windows, some of the drives may not contain media, so as long as at least one is ok..)
947 expect (numRootsExisting > 0);
950 beginTest ("Writing");
952 File demoFolder (temp.getChildFile ("Juce UnitTests Temp Folder.folder"));
953 expect (demoFolder.deleteRecursively());
954 expect (demoFolder.createDirectory());
955 expect (demoFolder.isDirectory());
956 expect (demoFolder.getParentDirectory() == temp);
957 expect (temp.isDirectory());
960 Array<File> files;
961 temp.findChildFiles (files, File::findFilesAndDirectories, false, "*");
962 expect (files.contains (demoFolder));
966 Array<File> files;
967 temp.findChildFiles (files, File::findDirectories, true, "*.folder");
968 expect (files.contains (demoFolder));
971 File tempFile (demoFolder.getNonexistentChildFile ("test", ".txt", false));
973 expect (tempFile.getFileExtension() == ".txt");
974 expect (tempFile.hasFileExtension (".txt"));
975 expect (tempFile.hasFileExtension ("txt"));
976 expect (tempFile.withFileExtension ("xyz").hasFileExtension (".xyz"));
977 expect (tempFile.withFileExtension ("xyz").hasFileExtension ("abc;xyz;foo"));
978 expect (tempFile.withFileExtension ("xyz").hasFileExtension ("xyz;foo"));
979 expect (! tempFile.withFileExtension ("h").hasFileExtension ("bar;foo;xx"));
980 expect (tempFile.getSiblingFile ("foo").isAChildOf (temp));
981 expect (tempFile.hasWriteAccess());
984 FileOutputStream fo (tempFile);
985 fo.write ("0123456789", 10);
988 expect (tempFile.exists());
989 expect (tempFile.getSize() == 10);
990 expect (std::abs ((int) (tempFile.getLastModificationTime().toMilliseconds() - Time::getCurrentTime().toMilliseconds())) < 3000);
991 expectEquals (tempFile.loadFileAsString(), String ("0123456789"));
992 expect (! demoFolder.containsSubDirectories());
994 expectEquals (tempFile.getRelativePathFrom (demoFolder.getParentDirectory()), demoFolder.getFileName() + File::separatorString + tempFile.getFileName());
995 expectEquals (demoFolder.getParentDirectory().getRelativePathFrom (tempFile), ".." + File::separatorString + ".." + File::separatorString + demoFolder.getParentDirectory().getFileName());
997 expect (demoFolder.getNumberOfChildFiles (File::findFiles) == 1);
998 expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 1);
999 expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 0);
1000 demoFolder.getNonexistentChildFile ("tempFolder", "", false).createDirectory();
1001 expect (demoFolder.getNumberOfChildFiles (File::findDirectories) == 1);
1002 expect (demoFolder.getNumberOfChildFiles (File::findFilesAndDirectories) == 2);
1003 expect (demoFolder.containsSubDirectories());
1005 expect (tempFile.hasWriteAccess());
1006 tempFile.setReadOnly (true);
1007 expect (! tempFile.hasWriteAccess());
1008 tempFile.setReadOnly (false);
1009 expect (tempFile.hasWriteAccess());
1011 Time t (Time::getCurrentTime());
1012 tempFile.setLastModificationTime (t);
1013 Time t2 = tempFile.getLastModificationTime();
1014 expect (std::abs ((int) (t2.toMilliseconds() - t.toMilliseconds())) <= 1000);
1017 MemoryBlock mb;
1018 tempFile.loadFileAsData (mb);
1019 expect (mb.getSize() == 10);
1020 expect (mb[0] == '0');
1023 beginTest ("Memory-mapped files");
1026 MemoryMappedFile mmf (tempFile, MemoryMappedFile::readOnly);
1027 expect (mmf.getSize() == 10);
1028 expect (mmf.getData() != nullptr);
1029 expect (memcmp (mmf.getData(), "0123456789", 10) == 0);
1033 const File tempFile2 (tempFile.getNonexistentSibling (false));
1034 expect (tempFile2.create());
1035 expect (tempFile2.appendData ("xxxxxxxxxx", 10));
1038 MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
1039 expect (mmf.getSize() == 10);
1040 expect (mmf.getData() != nullptr);
1041 memcpy (mmf.getData(), "abcdefghij", 10);
1045 MemoryMappedFile mmf (tempFile2, MemoryMappedFile::readWrite);
1046 expect (mmf.getSize() == 10);
1047 expect (mmf.getData() != nullptr);
1048 expect (memcmp (mmf.getData(), "abcdefghij", 10) == 0);
1051 expect (tempFile2.deleteFile());
1054 beginTest ("More writing");
1056 expect (tempFile.appendData ("abcdefghij", 10));
1057 expect (tempFile.getSize() == 20);
1058 expect (tempFile.replaceWithData ("abcdefghij", 10));
1059 expect (tempFile.getSize() == 10);
1061 File tempFile2 (tempFile.getNonexistentSibling (false));
1062 expect (tempFile.copyFileTo (tempFile2));
1063 expect (tempFile2.exists());
1064 expect (tempFile2.hasIdenticalContentTo (tempFile));
1065 expect (tempFile.deleteFile());
1066 expect (! tempFile.exists());
1067 expect (tempFile2.moveFileTo (tempFile));
1068 expect (tempFile.exists());
1069 expect (! tempFile2.exists());
1071 expect (demoFolder.deleteRecursively());
1072 expect (! demoFolder.exists());
1076 static FileTests fileUnitTests;
1078 #endif
1080 END_JUCE_NAMESPACE