From b11a88bc01bdee936ce7754c438cab4ecf4332c8 Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 15 Oct 2013 17:17:31 +0100 Subject: [PATCH] Moved some duplicated linux/android code into a shared file. Added a method File::isLink() --- modules/juce_core/files/juce_File.cpp | 2 + modules/juce_core/files/juce_File.h | 7 +- modules/juce_core/juce_core.cpp | 2 + .../juce_core/native/juce_android_Files.cpp | 142 +--------------- .../native/juce_linux_CommonFile.cpp | 153 ++++++++++++++++++ modules/juce_core/native/juce_linux_Files.cpp | 148 +---------------- modules/juce_core/native/juce_mac_Files.mm | 18 ++- modules/juce_core/native/juce_win32_Files.cpp | 13 +- 8 files changed, 193 insertions(+), 292 deletions(-) create mode 100644 modules/juce_core/native/juce_linux_CommonFile.cpp diff --git a/modules/juce_core/files/juce_File.cpp b/modules/juce_core/files/juce_File.cpp index b69b5a7962..b159770775 100644 --- a/modules/juce_core/files/juce_File.cpp +++ b/modules/juce_core/files/juce_File.cpp @@ -352,6 +352,8 @@ bool File::isAbsolutePath (StringRef path) File File::getChildFile (StringRef relativePath) const { + jassert (! relativePath.isEmpty()); // passing in an empty filename? + if (isAbsolutePath (relativePath)) return File (String (relativePath.text)); diff --git a/modules/juce_core/files/juce_File.h b/modules/juce_core/files/juce_File.h index 9ca381a690..6e4e6549eb 100644 --- a/modules/juce_core/files/juce_File.h +++ b/modules/juce_core/files/juce_File.h @@ -353,8 +353,11 @@ public: */ bool isHidden() const; - /** If this file is a link, this returns the file that it points to. - If this file isn't actually link, it'll just return itself. + /** Returns true if this file is a link or alias that can be followed using getLinkedTarget(). */ + bool isLink() const; + + /** If this file is a link or alias, this returns the file that it points to. + If the file isn't actually link, it'll just return itself. */ File getLinkedTarget() const; diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp index 04fea71165..fa7c19c0da 100644 --- a/modules/juce_core/juce_core.cpp +++ b/modules/juce_core/juce_core.cpp @@ -198,6 +198,7 @@ namespace juce //============================================================================== #elif JUCE_LINUX +#include "native/juce_linux_CommonFile.cpp" #include "native/juce_linux_Files.cpp" #include "native/juce_linux_Network.cpp" #include "native/juce_linux_SystemStats.cpp" @@ -205,6 +206,7 @@ namespace juce //============================================================================== #elif JUCE_ANDROID +#include "native/juce_linux_CommonFile.cpp" #include "native/juce_android_Files.cpp" #include "native/juce_android_Misc.cpp" #include "native/juce_android_Network.cpp" diff --git a/modules/juce_core/native/juce_android_Files.cpp b/modules/juce_core/native/juce_android_Files.cpp index 5727581a81..18180435dc 100644 --- a/modules/juce_core/native/juce_android_Files.cpp +++ b/modules/juce_core/native/juce_android_Files.cpp @@ -26,34 +26,6 @@ ============================================================================== */ -bool File::copyInternal (const File& dest) const -{ - FileInputStream in (*this); - - if (dest.deleteFile()) - { - { - FileOutputStream out (dest); - - if (out.failedToOpen()) - return false; - - if (out.writeFromInputStream (in, -1) == getSize()) - return true; - } - - dest.deleteFile(); - } - - return false; -} - -void File::findFileSystemRoots (Array& destArray) -{ - destArray.add (File ("/")); -} - -//============================================================================== bool File::isOnCDRomDrive() const { return false; @@ -69,35 +41,11 @@ bool File::isOnRemovableDrive() const return false; } -bool File::isHidden() const +String File::getVersion() const { - return getFileName().startsWithChar ('.'); + return String::empty; } -//============================================================================== -namespace -{ - File juce_readlink (const String& file, const File& defaultFile) - { - const int size = 8192; - HeapBlock buffer; - buffer.malloc (size + 4); - - const size_t numBytes = readlink (file.toUTF8(), buffer, size); - - if (numBytes > 0 && numBytes <= size) - return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes)); - - return defaultFile; - } -} - -File File::getLinkedTarget() const -{ - return juce_readlink (getFullPathName().toUTF8(), *this); -} - -//============================================================================== File File::getSpecialLocation (const SpecialLocationType type) { switch (type) @@ -135,101 +83,15 @@ File File::getSpecialLocation (const SpecialLocationType type) return File::nonexistent; } -//============================================================================== -String File::getVersion() const -{ - return String::empty; -} - -//============================================================================== bool File::moveToTrash() const { if (! exists()) return true; // TODO - return false; } -//============================================================================== -class DirectoryIterator::NativeIterator::Pimpl -{ -public: - Pimpl (const File& directory, const String& wildCard_) - : parentDir (File::addTrailingSeparator (directory.getFullPathName())), - wildCard (wildCard_), - dir (opendir (directory.getFullPathName().toUTF8())) - { - } - - ~Pimpl() - { - if (dir != 0) - closedir (dir); - } - - bool next (String& filenameFound, - bool* const isDir, bool* const isHidden, int64* const fileSize, - Time* const modTime, Time* const creationTime, bool* const isReadOnly) - { - if (dir != 0) - { - const char* wildcardUTF8 = nullptr; - - for (;;) - { - struct dirent* const de = readdir (dir); - - if (de == nullptr) - break; - - if (wildcardUTF8 == nullptr) - wildcardUTF8 = wildCard.toUTF8(); - - if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0) - { - filenameFound = CharPointer_UTF8 (de->d_name); - - updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly); - - if (isHidden != 0) - *isHidden = filenameFound.startsWithChar ('.'); - - return true; - } - } - } - - return false; - } - -private: - String parentDir, wildCard; - DIR* dir; - - JUCE_DECLARE_NON_COPYABLE (Pimpl) -}; - - -DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard) - : pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard)) -{ -} - -DirectoryIterator::NativeIterator::~NativeIterator() -{ -} - -bool DirectoryIterator::NativeIterator::next (String& filenameFound, - bool* const isDir, bool* const isHidden, int64* const fileSize, - Time* const modTime, Time* const creationTime, bool* const isReadOnly) -{ - return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly); -} - - -//============================================================================== JUCE_API bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters) { const LocalRef t (javaString (fileName)); diff --git a/modules/juce_core/native/juce_linux_CommonFile.cpp b/modules/juce_core/native/juce_linux_CommonFile.cpp new file mode 100644 index 0000000000..2ce98b3bda --- /dev/null +++ b/modules/juce_core/native/juce_linux_CommonFile.cpp @@ -0,0 +1,153 @@ +/* + ============================================================================== + + This file is part of the juce_core module of the JUCE library. + Copyright (c) 2013 - Raw Material Software Ltd. + + Permission to use, copy, modify, and/or distribute this software for any purpose with + or without fee is hereby granted, provided that the above copyright notice and this + permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ------------------------------------------------------------------------------ + + NOTE! This permissive ISC license applies ONLY to files within the juce_core module! + All other JUCE modules are covered by a dual GPL/commercial license, so if you are + using any other modules, be sure to check that you also comply with their license. + + For more details, visit www.juce.com + + ============================================================================== +*/ + +bool File::copyInternal (const File& dest) const +{ + FileInputStream in (*this); + + if (dest.deleteFile()) + { + { + FileOutputStream out (dest); + + if (out.failedToOpen()) + return false; + + if (out.writeFromInputStream (in, -1) == getSize()) + return true; + } + + dest.deleteFile(); + } + + return false; +} + +void File::findFileSystemRoots (Array& destArray) +{ + destArray.add (File ("/")); +} + +bool File::isHidden() const +{ + return getFileName().startsWithChar ('.'); +} + +static String getLinkedFile (StringRef file) +{ + HeapBlock buffer (8194); + const int numBytes = (int) readlink (file.text, buffer, 8192); + return String::fromUTF8 (buffer, jmax (0, numBytes)); +}; + +bool File::isLink() const +{ + return getLinkedFile (getFullPathName()).isNotEmpty(); +} + +File File::getLinkedTarget() const +{ + String f (getLinkedFile (getFullPathName())); + + if (f.isNotEmpty()) + return getSiblingFile (f); + + return *this; +} + +//============================================================================== +class DirectoryIterator::NativeIterator::Pimpl +{ +public: + Pimpl (const File& directory, const String& wc) + : parentDir (File::addTrailingSeparator (directory.getFullPathName())), + wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8())) + { + } + + ~Pimpl() + { + if (dir != nullptr) + closedir (dir); + } + + bool next (String& filenameFound, + bool* const isDir, bool* const isHidden, int64* const fileSize, + Time* const modTime, Time* const creationTime, bool* const isReadOnly) + { + if (dir != nullptr) + { + const char* wildcardUTF8 = nullptr; + + for (;;) + { + struct dirent* const de = readdir (dir); + + if (de == nullptr) + break; + + if (wildcardUTF8 == nullptr) + wildcardUTF8 = wildCard.toUTF8(); + + if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0) + { + filenameFound = CharPointer_UTF8 (de->d_name); + + updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly); + + if (isHidden != nullptr) + *isHidden = filenameFound.startsWithChar ('.'); + + return true; + } + } + } + + return false; + } + +private: + String parentDir, wildCard; + DIR* dir; + + JUCE_DECLARE_NON_COPYABLE (Pimpl) +}; + +DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard) + : pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard)) +{ +} + +DirectoryIterator::NativeIterator::~NativeIterator() {} + +bool DirectoryIterator::NativeIterator::next (String& filenameFound, + bool* isDir, bool* isHidden, int64* fileSize, + Time* modTime, Time* creationTime, bool* isReadOnly) +{ + return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly); +} diff --git a/modules/juce_core/native/juce_linux_Files.cpp b/modules/juce_core/native/juce_linux_Files.cpp index c3d97c0755..68a5bceec8 100644 --- a/modules/juce_core/native/juce_linux_Files.cpp +++ b/modules/juce_core/native/juce_linux_Files.cpp @@ -34,35 +34,6 @@ enum U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h }; -//============================================================================== -bool File::copyInternal (const File& dest) const -{ - FileInputStream in (*this); - - if (dest.deleteFile()) - { - { - FileOutputStream out (dest); - - if (out.failedToOpen()) - return false; - - if (out.writeFromInputStream (in, -1) == getSize()) - return true; - } - - dest.deleteFile(); - } - - return false; -} - -void File::findFileSystemRoots (Array& destArray) -{ - destArray.add (File ("/")); -} - -//============================================================================== bool File::isOnCDRomDrive() const { struct statfs buf; @@ -85,11 +56,7 @@ bool File::isOnHardDisk() const case U_SMB_SUPER_MAGIC: // Network Samba return false; - default: - // Assume anything else is a hard-disk (but note it could - // be a RAM disk. There isn't a good way of determining - // this for sure) - return true; + default: break; } } @@ -103,32 +70,9 @@ bool File::isOnRemovableDrive() const return false; } -bool File::isHidden() const +String File::getVersion() const { - return getFileName().startsWithChar ('.'); -} - -//============================================================================== -namespace -{ - File juce_readlink (const String& file, const File& defaultFile) - { - const size_t size = 8192; - HeapBlock buffer; - buffer.malloc (size + 4); - - const size_t numBytes = readlink (file.toUTF8(), buffer, size); - - if (numBytes > 0 && numBytes <= size) - return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes)); - - return defaultFile; - } -} - -File File::getLinkedTarget() const -{ - return juce_readlink (getFullPathName().toUTF8(), *this); + return String::empty; // xxx not yet implemented } //============================================================================== @@ -209,7 +153,10 @@ File File::getSpecialLocation (const SpecialLocationType type) return juce_getExecutableFile(); case hostApplicationPath: - return juce_readlink ("/proc/self/exe", juce_getExecutableFile()); + { + const File f ("/proc/self/exe"); + return f.isLink() ? f.getLinkedTarget() : juce_getExecutableFile(); + } default: jassertfalse; // unknown type? @@ -219,12 +166,6 @@ File File::getSpecialLocation (const SpecialLocationType type) return File::nonexistent; } -//============================================================================== -String File::getVersion() const -{ - return String::empty; // xxx not yet implemented -} - //============================================================================== bool File::moveToTrash() const { @@ -243,81 +184,6 @@ bool File::moveToTrash() const getFileExtension())); } -//============================================================================== -class DirectoryIterator::NativeIterator::Pimpl -{ -public: - Pimpl (const File& directory, const String& wc) - : parentDir (File::addTrailingSeparator (directory.getFullPathName())), - wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8())) - { - } - - ~Pimpl() - { - if (dir != nullptr) - closedir (dir); - } - - bool next (String& filenameFound, - bool* const isDir, bool* const isHidden, int64* const fileSize, - Time* const modTime, Time* const creationTime, bool* const isReadOnly) - { - if (dir != nullptr) - { - const char* wildcardUTF8 = nullptr; - - for (;;) - { - struct dirent* const de = readdir (dir); - - if (de == nullptr) - break; - - if (wildcardUTF8 == nullptr) - wildcardUTF8 = wildCard.toUTF8(); - - if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0) - { - filenameFound = CharPointer_UTF8 (de->d_name); - - updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly); - - if (isHidden != nullptr) - *isHidden = filenameFound.startsWithChar ('.'); - - return true; - } - } - } - - return false; - } - -private: - String parentDir, wildCard; - DIR* dir; - - JUCE_DECLARE_NON_COPYABLE (Pimpl) -}; - -DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard) - : pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard)) -{ -} - -DirectoryIterator::NativeIterator::~NativeIterator() -{ -} - -bool DirectoryIterator::NativeIterator::next (String& filenameFound, - bool* const isDir, bool* const isHidden, int64* const fileSize, - Time* const modTime, Time* const creationTime, bool* const isReadOnly) -{ - return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly); -} - - //============================================================================== static bool isFileExecutable (const String& filename) { diff --git a/modules/juce_core/native/juce_mac_Files.mm b/modules/juce_core/native/juce_mac_Files.mm index c55272415c..cdebc59e07 100644 --- a/modules/juce_core/native/juce_mac_Files.mm +++ b/modules/juce_core/native/juce_mac_Files.mm @@ -275,17 +275,25 @@ String File::getVersion() const } //============================================================================== -File File::getLinkedTarget() const +static NSString* getFileLink (const String& path) { #if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) - NSString* dest = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: juceStringToNS (getFullPathName()) error: nil]; + return [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: juceStringToNS (path) error: nil]; #else // (the cast here avoids a deprecation warning) - NSString* dest = [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: juceStringToNS (getFullPathName())]; + return [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: juceStringToNS (path)]; #endif +} - if (dest != nil) - return File (nsStringToJuce (dest)); +bool File::isLink() const +{ + return getFileLink (fullPath) != nil; +} + +File File::getLinkedTarget() const +{ + if (NSString* dest = getFileLink (fullPath)) + return getSiblingFile (nsStringToJuce (dest)); return *this; } diff --git a/modules/juce_core/native/juce_win32_Files.cpp b/modules/juce_core/native/juce_win32_Files.cpp index 8c8ab918c7..6f724846a5 100644 --- a/modules/juce_core/native/juce_win32_Files.cpp +++ b/modules/juce_core/native/juce_win32_Files.cpp @@ -590,6 +590,11 @@ String File::getVersion() const } //============================================================================== +bool File::isLink() const +{ + return hasFileExtension (".lnk"); +} + File File::getLinkedTarget() const { File result (*this); @@ -600,8 +605,8 @@ File File::getLinkedTarget() const else if (! hasFileExtension (".lnk")) return result; - ComSmartPtr shellLink; - ComSmartPtr persistFile; + ComSmartPtr shellLink; + ComSmartPtr persistFile; if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink)) && SUCCEEDED (shellLink.QueryInterface (persistFile)) @@ -622,8 +627,8 @@ bool File::createLink (const String& description, const File& linkFileToCreate) { linkFileToCreate.deleteFile(); - ComSmartPtr shellLink; - ComSmartPtr persistFile; + ComSmartPtr shellLink; + ComSmartPtr persistFile; return SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink)) && SUCCEEDED (shellLink->SetPath (getFullPathName().toWideCharPointer()))