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(mozIDOMWindowProxy
* aParent
, const nsAString
& aTitle
,
29 nsIFilePicker::Mode aMode
,
30 BrowsingContext
* aBrowsingContext
) {
31 BrowserChild
* browserChild
= BrowserChild::GetFrom(aParent
);
33 return NS_ERROR_FAILURE
;
36 mParent
= nsPIDOMWindowOuter::From(aParent
);
40 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
;
124 nsresult
nsFilePickerProxy::Show(nsIFilePicker::ResultCode
* aReturn
) {
125 MOZ_ASSERT(false, "Show is unimplemented; use Open");
126 return NS_ERROR_NOT_IMPLEMENTED
;
130 nsFilePickerProxy::Open(nsIFilePickerShownCallback
* aCallback
) {
131 mCallback
= aCallback
;
133 nsString displayDirectory
;
134 if (mDisplayDirectory
) {
135 mDisplayDirectory
->GetPath(displayDirectory
);
139 return NS_ERROR_FAILURE
;
142 SendOpen(mSelectedType
, mAddToRecentDocs
, mDefault
, mDefaultExtension
,
143 mFilters
, mFilterNames
, mRawFilters
, displayDirectory
,
144 mDisplaySpecialDirectory
, mOkButtonLabel
, mCapture
);
150 nsFilePickerProxy::Close() {
156 mozilla::ipc::IPCResult
nsFilePickerProxy::Recv__delete__(
157 const MaybeInputData
& aData
, const nsIFilePicker::ResultCode
& aResult
) {
158 nsPIDOMWindowInner
* inner
=
159 mParent
? mParent
->GetCurrentInnerWindow() : nullptr;
161 if (NS_WARN_IF(!inner
)) {
165 if (aData
.type() == MaybeInputData::TInputBlobs
) {
166 const nsTArray
<IPCBlob
>& blobs
= aData
.get_InputBlobs().blobs();
167 for (uint32_t i
= 0; i
< blobs
.Length(); ++i
) {
168 RefPtr
<BlobImpl
> blobImpl
= IPCBlobUtils::Deserialize(blobs
[i
]);
169 NS_ENSURE_TRUE(blobImpl
, IPC_OK());
171 if (!blobImpl
->IsFile()) {
175 RefPtr
<File
> file
= File::Create(inner
->AsGlobal(), blobImpl
);
176 if (NS_WARN_IF(!file
)) {
180 OwningFileOrDirectory
* element
= mFilesOrDirectories
.AppendElement();
181 element
->SetAsFile() = file
;
183 } else if (aData
.type() == MaybeInputData::TInputDirectory
) {
184 nsCOMPtr
<nsIFile
> file
;
185 const nsAString
& path(aData
.get_InputDirectory().directoryPath());
186 nsresult rv
= NS_NewLocalFile(path
, true, getter_AddRefs(file
));
187 if (NS_WARN_IF(NS_FAILED(rv
))) {
191 RefPtr
<Directory
> directory
= Directory::Create(inner
->AsGlobal(), file
);
192 MOZ_ASSERT(directory
);
194 OwningFileOrDirectory
* element
= mFilesOrDirectories
.AppendElement();
195 element
->SetAsDirectory() = directory
;
199 mCallback
->Done(aResult
);
207 nsFilePickerProxy::GetDomFileOrDirectory(nsISupports
** aValue
) {
209 if (mFilesOrDirectories
.IsEmpty()) {
213 MOZ_ASSERT(mFilesOrDirectories
.Length() == 1);
215 if (mFilesOrDirectories
[0].IsFile()) {
216 nsCOMPtr
<nsISupports
> blob
= ToSupports(mFilesOrDirectories
[0].GetAsFile());
221 MOZ_ASSERT(mFilesOrDirectories
[0].IsDirectory());
222 RefPtr
<Directory
> directory
= mFilesOrDirectories
[0].GetAsDirectory();
223 directory
.forget(aValue
);
229 class SimpleEnumerator final
: public nsSimpleEnumerator
{
231 explicit SimpleEnumerator(
232 const nsTArray
<OwningFileOrDirectory
>& aFilesOrDirectories
)
233 : mFilesOrDirectories(aFilesOrDirectories
.Clone()), mIndex(0) {}
236 HasMoreElements(bool* aRetvalue
) override
{
237 MOZ_ASSERT(aRetvalue
);
238 *aRetvalue
= mIndex
< mFilesOrDirectories
.Length();
243 GetNext(nsISupports
** aValue
) override
{
244 NS_ENSURE_TRUE(mIndex
< mFilesOrDirectories
.Length(), NS_ERROR_FAILURE
);
246 uint32_t index
= mIndex
++;
248 if (mFilesOrDirectories
[index
].IsFile()) {
249 nsCOMPtr
<nsISupports
> blob
=
250 ToSupports(mFilesOrDirectories
[index
].GetAsFile());
255 MOZ_ASSERT(mFilesOrDirectories
[index
].IsDirectory());
256 RefPtr
<Directory
> directory
= mFilesOrDirectories
[index
].GetAsDirectory();
257 directory
.forget(aValue
);
262 nsTArray
<mozilla::dom::OwningFileOrDirectory
> mFilesOrDirectories
;
269 nsFilePickerProxy::GetDomFileOrDirectoryEnumerator(
270 nsISimpleEnumerator
** aDomfiles
) {
271 RefPtr
<SimpleEnumerator
> enumerator
=
272 new SimpleEnumerator(mFilesOrDirectories
);
273 enumerator
.forget(aDomfiles
);
277 void nsFilePickerProxy::ActorDestroy(ActorDestroyReason aWhy
) {
281 mCallback
->Done(nsIFilePicker::returnCancel
);
286 nsresult
nsFilePickerProxy::ResolveSpecialDirectory(
287 const nsAString
& aSpecialDirectory
) {
288 MOZ_ASSERT(XRE_IsContentProcess());
289 // Resolving the special-directory name to a path in both the child and parent
290 // processes is redundant -- and sandboxing may prevent us from doing so in
291 // the child process, anyway. (See bugs 1357846 and 1838244.)
293 // Unfortunately we can't easily verify that `aSpecialDirectory` is usable or
294 // even meaningful here, so we just accept anything.