From 7297f621823314456559b4a1d0e37cc67bcd77ad Mon Sep 17 00:00:00 2001 From: Lukasz Kozakiewicz Date: Wed, 29 Nov 2017 21:59:18 +0100 Subject: [PATCH] FileChooser: actually do store URL security bookmark in a smart pointer (as it was originally on an internal branch). Also update the docs to clearly indicate that a user has to use URL returned from FileChooser. --- modules/juce_core/network/juce_URL.cpp | 23 +++++++++++++++---- modules/juce_core/network/juce_URL.h | 12 +++++++++- .../filebrowser/juce_FileChooser.h | 22 +++++++++++++----- .../native/juce_ios_FileChooser.mm | 2 ++ 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/modules/juce_core/network/juce_URL.cpp b/modules/juce_core/network/juce_URL.cpp index d87a1b0de4..cc8e1485f0 100644 --- a/modules/juce_core/network/juce_URL.cpp +++ b/modules/juce_core/network/juce_URL.cpp @@ -198,7 +198,7 @@ URL::URL (URL&& other) parameterValues (static_cast (other.parameterValues)), filesToUpload (static_cast&&> (other.filesToUpload)) #if JUCE_IOS - , bookmark (other.bookmark) + , bookmark (static_cast (other.bookmark)) #endif { } @@ -210,8 +210,8 @@ URL& URL::operator= (URL&& other) parameterNames = static_cast (other.parameterNames); parameterValues = static_cast (other.parameterValues); filesToUpload = static_cast&&> (other.filesToUpload); - #if JUCE_IOS - bookmark = other.bookmark; + #if JUCE_IOS + bookmark = static_cast (other.bookmark); #endif return *this; @@ -501,14 +501,27 @@ bool URL::isProbablyAnEmailAddress (const String& possibleEmailAddress) } #if JUCE_IOS +URL::Bookmark::Bookmark (void* bookmarkToUse) + : data (bookmarkToUse) +{ +} + +URL::Bookmark::~Bookmark() +{ + [(NSData*) data release]; +} + void setURLBookmark (URL& u, void* bookmark) { - u.bookmark = bookmark; + u.bookmark = new URL::Bookmark (bookmark); } void* getURLBookmark (URL& u) { - return u.bookmark; + if (u.bookmark.get() == nullptr) + return nullptr; + + return u.bookmark.get()->data; } template struct iOSFileStreamWrapperFlush { static void flush (Stream*) {} }; diff --git a/modules/juce_core/network/juce_URL.h b/modules/juce_core/network/juce_URL.h index 13660940e3..4ff069a1ee 100644 --- a/modules/juce_core/network/juce_URL.h +++ b/modules/juce_core/network/juce_URL.h @@ -529,7 +529,17 @@ private: ReferenceCountedArray filesToUpload; #if JUCE_IOS - void* bookmark; + struct Bookmark : public ReferenceCountedObject + { + using Ptr = ReferenceCountedObjectPtr; + + Bookmark (void*); + ~Bookmark(); + + void* data; + }; + + Bookmark::Ptr bookmark; friend void setURLBookmark (URL&, void*); friend void* getURLBookmark (URL&); diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooser.h b/modules/juce_gui_basics/filebrowser/juce_FileChooser.h index 6bbac4ffbf..a720b63a3c 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooser.h +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooser.h @@ -237,9 +237,14 @@ public: may return a URL to a remote document. If a local file is chosen then you can convert this file to a JUCE File class via the URL::getLocalFile method. - Note: on iOS it is best to dispose any copies of returned URL as soon as - you finish dealing with the file. This is because URL might be security - scoped and a system allows only for a limited number of such URLs. + Note: on iOS you must use the returned URL object directly (you are also + allowed to copy- or move-construct another URL from the returned URL), rather + than just storing the path as a String and then creating a new URL from that + String. This is because the returned URL contains internally a security + bookmark that is required to access the files pointed by it. Then, once you stop + dealing with the file pointed by the URL, you should dispose that URL object, + so that the security bookmark can be released by the system (only a limited + number of such URLs is allowed). @see getResult, URL::getLocalFile */ @@ -255,9 +260,14 @@ public: This array may be empty if no files were chosen, or can contain multiple entries if multiple files were chosen. - Note: on iOS it is best to dispose any copies of returned URLs as soon as - you finish dealing with the file. This is because URLs might be security - scoped and a system allows only for a limited number of such URLs. + Note: on iOS you must use the returned URL object directly (you are also + allowed to copy- or move-construct another URL from the returned URL), rather + than just storing the path as a String and then creating a new URL from that + String. This is because the returned URL contains internally a security + bookmark that is required to access the files pointed by it. Then, once you stop + dealing with the file pointed by the URL, you should dispose that URL object, + so that the security bookmark can be released by the system (only a limited + number of such URLs is allowed). @see getResults, URL::getLocalFile */ diff --git a/modules/juce_gui_basics/native/juce_ios_FileChooser.mm b/modules/juce_gui_basics/native/juce_ios_FileChooser.mm index 09e09f8e9a..b0b474b79a 100644 --- a/modules/juce_gui_basics/native/juce_ios_FileChooser.mm +++ b/modules/juce_gui_basics/native/juce_ios_FileChooser.mm @@ -217,6 +217,8 @@ private: relativeToURL: nil error: &error]; + [bookmark retain]; + [url stopAccessingSecurityScopedResource]; URL juceUrl (nsStringToJuce ([url absoluteString]));