1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsFilePickerProxy.h"
8 #include "nsComponentManagerUtils.h"
10 #include "nsSimpleEnumerator.h"
11 #include "mozilla/dom/BlobImpl.h"
12 #include "mozilla/dom/Directory.h"
13 #include "mozilla/dom/File.h"
14 #include "mozilla/dom/BrowserChild.h"
15 #include "mozilla/dom/BrowsingContext.h"
16 #include "mozilla/dom/IPCBlobUtils.h"
18 using namespace mozilla::dom
;
20 NS_IMPL_ISUPPORTS(nsFilePickerProxy
, nsIFilePicker
)
22 nsFilePickerProxy::nsFilePickerProxy()
23 : mSelectedType(0), mCapture(captureNone
), mIPCActive(false) {}
25 nsFilePickerProxy::~nsFilePickerProxy() = default;
28 nsFilePickerProxy::Init(BrowsingContext
* aBrowsingContext
,
29 const nsAString
& aTitle
, nsIFilePicker::Mode aMode
) {
30 BrowserChild
* browserChild
=
31 BrowserChild::GetFrom(aBrowsingContext
->GetDocShell());
33 return NS_ERROR_FAILURE
;
36 mBrowsingContext
= aBrowsingContext
;
39 browserChild
->SendPFilePickerConstructor(this, aTitle
, aMode
,
46 void nsFilePickerProxy::InitNative(nsIWidget
* aParent
,
47 const nsAString
& aTitle
) {}
50 nsFilePickerProxy::AppendFilter(const nsAString
& aTitle
,
51 const nsAString
& aFilter
) {
52 mFilterNames
.AppendElement(aTitle
);
53 mFilters
.AppendElement(aFilter
);
58 nsFilePickerProxy::GetCapture(nsIFilePicker::CaptureTarget
* aCapture
) {
64 nsFilePickerProxy::SetCapture(nsIFilePicker::CaptureTarget aCapture
) {
70 nsFilePickerProxy::GetDefaultString(nsAString
& aDefaultString
) {
71 aDefaultString
= mDefault
;
76 nsFilePickerProxy::SetDefaultString(const nsAString
& aDefaultString
) {
77 mDefault
= aDefaultString
;
82 nsFilePickerProxy::GetDefaultExtension(nsAString
& aDefaultExtension
) {
83 aDefaultExtension
= mDefaultExtension
;
88 nsFilePickerProxy::SetDefaultExtension(const nsAString
& aDefaultExtension
) {
89 mDefaultExtension
= aDefaultExtension
;
94 nsFilePickerProxy::GetFilterIndex(int32_t* aFilterIndex
) {
95 *aFilterIndex
= mSelectedType
;
100 nsFilePickerProxy::SetFilterIndex(int32_t aFilterIndex
) {
101 mSelectedType
= aFilterIndex
;
106 nsFilePickerProxy::GetFile(nsIFile
** aFile
) {
107 MOZ_ASSERT(false, "GetFile is unimplemented; use GetDomFileOrDirectory");
108 return NS_ERROR_FAILURE
;
112 nsFilePickerProxy::GetFileURL(nsIURI
** aFileURL
) {
113 MOZ_ASSERT(false, "GetFileURL is unimplemented; use GetDomFileOrDirectory");
114 return NS_ERROR_FAILURE
;
118 nsFilePickerProxy::GetFiles(nsISimpleEnumerator
** aFiles
) {
120 "GetFiles is unimplemented; use GetDomFileOrDirectoryEnumerator");
121 return NS_ERROR_FAILURE
;
125 nsFilePickerProxy::Open(nsIFilePickerShownCallback
* aCallback
) {
126 mCallback
= aCallback
;
128 nsString displayDirectory
;
129 if (mDisplayDirectory
) {
130 mDisplayDirectory
->GetPath(displayDirectory
);
134 return NS_ERROR_FAILURE
;
137 SendOpen(mSelectedType
, mAddToRecentDocs
, mDefault
, mDefaultExtension
,
138 mFilters
, mFilterNames
, mRawFilters
, displayDirectory
,
139 mDisplaySpecialDirectory
, mOkButtonLabel
, mCapture
);
144 mozilla::ipc::IPCResult
nsFilePickerProxy::Recv__delete__(
145 const MaybeInputData
& aData
, const nsIFilePicker::ResultCode
& aResult
) {
146 auto* inner
= mBrowsingContext
->GetDOMWindow()
147 ? mBrowsingContext
->GetDOMWindow()->GetCurrentInnerWindow()
150 if (NS_WARN_IF(!inner
)) {
154 if (aData
.type() == MaybeInputData::TInputBlobs
) {
155 const nsTArray
<IPCBlob
>& blobs
= aData
.get_InputBlobs().blobs();
156 for (uint32_t i
= 0; i
< blobs
.Length(); ++i
) {
157 RefPtr
<BlobImpl
> blobImpl
= IPCBlobUtils::Deserialize(blobs
[i
]);
158 NS_ENSURE_TRUE(blobImpl
, IPC_OK());
160 if (!blobImpl
->IsFile()) {
164 RefPtr
<File
> file
= File::Create(inner
->AsGlobal(), blobImpl
);
165 if (NS_WARN_IF(!file
)) {
169 OwningFileOrDirectory
* element
= mFilesOrDirectories
.AppendElement();
170 element
->SetAsFile() = file
;
172 } else if (aData
.type() == MaybeInputData::TInputDirectory
) {
173 nsCOMPtr
<nsIFile
> file
;
174 const nsAString
& path(aData
.get_InputDirectory().directoryPath());
175 nsresult rv
= NS_NewLocalFile(path
, getter_AddRefs(file
));
176 if (NS_WARN_IF(NS_FAILED(rv
))) {
180 RefPtr
<Directory
> directory
= Directory::Create(inner
->AsGlobal(), file
);
181 MOZ_ASSERT(directory
);
183 OwningFileOrDirectory
* element
= mFilesOrDirectories
.AppendElement();
184 element
->SetAsDirectory() = directory
;
188 mCallback
->Done(aResult
);
196 nsFilePickerProxy::GetDomFileOrDirectory(nsISupports
** aValue
) {
198 if (mFilesOrDirectories
.IsEmpty()) {
202 MOZ_ASSERT(mFilesOrDirectories
.Length() == 1);
204 if (mFilesOrDirectories
[0].IsFile()) {
205 nsCOMPtr
<nsISupports
> blob
= ToSupports(mFilesOrDirectories
[0].GetAsFile());
210 MOZ_ASSERT(mFilesOrDirectories
[0].IsDirectory());
211 RefPtr
<Directory
> directory
= mFilesOrDirectories
[0].GetAsDirectory();
212 directory
.forget(aValue
);
218 class SimpleEnumerator final
: public nsSimpleEnumerator
{
220 explicit SimpleEnumerator(
221 const nsTArray
<OwningFileOrDirectory
>& aFilesOrDirectories
)
222 : mFilesOrDirectories(aFilesOrDirectories
.Clone()), mIndex(0) {}
225 HasMoreElements(bool* aRetvalue
) override
{
226 MOZ_ASSERT(aRetvalue
);
227 *aRetvalue
= mIndex
< mFilesOrDirectories
.Length();
232 GetNext(nsISupports
** aValue
) override
{
233 NS_ENSURE_TRUE(mIndex
< mFilesOrDirectories
.Length(), NS_ERROR_FAILURE
);
235 uint32_t index
= mIndex
++;
237 if (mFilesOrDirectories
[index
].IsFile()) {
238 nsCOMPtr
<nsISupports
> blob
=
239 ToSupports(mFilesOrDirectories
[index
].GetAsFile());
244 MOZ_ASSERT(mFilesOrDirectories
[index
].IsDirectory());
245 RefPtr
<Directory
> directory
= mFilesOrDirectories
[index
].GetAsDirectory();
246 directory
.forget(aValue
);
251 nsTArray
<mozilla::dom::OwningFileOrDirectory
> mFilesOrDirectories
;
258 nsFilePickerProxy::GetDomFileOrDirectoryEnumerator(
259 nsISimpleEnumerator
** aDomfiles
) {
260 RefPtr
<SimpleEnumerator
> enumerator
=
261 new SimpleEnumerator(mFilesOrDirectories
);
262 enumerator
.forget(aDomfiles
);
266 void nsFilePickerProxy::ActorDestroy(ActorDestroyReason aWhy
) {
270 mCallback
->Done(nsIFilePicker::returnCancel
);
275 nsresult
nsFilePickerProxy::ResolveSpecialDirectory(
276 const nsAString
& aSpecialDirectory
) {
277 MOZ_ASSERT(XRE_IsContentProcess());
278 // Resolving the special-directory name to a path in both the child and parent
279 // processes is redundant -- and sandboxing may prevent us from doing so in
280 // the child process, anyway. (See bugs 1357846 and 1838244.)
282 // Unfortunately we can't easily verify that `aSpecialDirectory` is usable or
283 // even meaningful here, so we just accept anything.