1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 - at some point, strings will be accessible from JS, so we won't have to wrap
10 flavors in an nsISupportsCString. Until then, we're kinda stuck with
11 this crappy API of nsIArrays.
15 #include "nsTransferable.h"
16 #include "nsAnonymousTemporaryFile.h"
18 #include "nsArrayUtils.h"
20 #include "nsReadableUtils.h"
22 #include "nsIFormatConverter.h"
23 #include "nsIContentPolicy.h"
26 #include "nsISupportsPrimitives.h"
27 #include "nsPrimitiveHelpers.h"
28 #include "nsDirectoryServiceDefs.h"
29 #include "nsDirectoryService.h"
31 #include "nsNetUtil.h"
32 #include "nsILoadContext.h"
33 #include "nsXULAppAPI.h"
34 #include "mozilla/StaticPrefs_browser.h"
35 #include "mozilla/UniquePtr.h"
37 using namespace mozilla
;
39 NS_IMPL_ISUPPORTS(nsTransferable
, nsITransferable
)
41 DataStruct::DataStruct(DataStruct
&& aRHS
)
42 : mData(aRHS
.mData
.forget()),
43 mCacheFD(aRHS
.mCacheFD
),
44 mFlavor(aRHS
.mFlavor
) {
45 aRHS
.mCacheFD
= nullptr;
48 //-------------------------------------------------------------------------
49 DataStruct::~DataStruct() {
55 //-------------------------------------------------------------------------
57 void DataStruct::SetData(nsISupports
* aData
, bool aIsPrivateData
) {
58 // Now, check to see if we consider the data to be "too large"
59 // as well as ensuring that private browsing mode is disabled.
60 // File IO is not allowed in content processes.
61 if (!aIsPrivateData
&& XRE_IsParentProcess()) {
64 nsPrimitiveHelpers::CreateDataFromPrimitive(mFlavor
, aData
, &data
,
67 if (dataLen
> kLargeDatasetSize
) {
68 // Too large, cache it to disk instead of memory.
69 if (NS_SUCCEEDED(WriteCache(data
, dataLen
))) {
71 // Clear previously set small data.
76 NS_WARNING("Oh no, couldn't write data to the cache file");
83 // Clear previously set big data.
91 //-------------------------------------------------------------------------
92 void DataStruct::GetData(nsISupports
** aData
) {
93 // check here to see if the data is cached on disk
95 // if so, read it in and pass it back
96 // ReadCache creates memory and copies the data into it.
97 if (NS_SUCCEEDED(ReadCache(aData
))) {
101 // oh shit, something went horribly wrong here.
102 NS_WARNING("Oh no, couldn't read data in from the cache file");
109 nsCOMPtr
<nsISupports
> data
= mData
;
113 //-------------------------------------------------------------------------
114 nsresult
DataStruct::WriteCache(void* aData
, uint32_t aDataLen
) {
115 MOZ_ASSERT(aData
&& aDataLen
);
116 MOZ_ASSERT(aDataLen
<= uint32_t(std::numeric_limits
<int32_t>::max()),
117 "too large size for PR_Write");
121 rv
= NS_OpenAnonymousTemporaryFile(&mCacheFD
);
123 return NS_ERROR_FAILURE
;
125 } else if (PR_Seek64(mCacheFD
, 0, PR_SEEK_SET
) == -1) {
126 return NS_ERROR_FAILURE
;
129 // Write out the contents of the clipboard to the file.
130 int32_t written
= PR_Write(mCacheFD
, aData
, aDataLen
);
131 if (written
== int32_t(aDataLen
)) {
137 return NS_ERROR_FAILURE
;
140 //-------------------------------------------------------------------------
141 nsresult
DataStruct::ReadCache(nsISupports
** aData
) {
143 return NS_ERROR_FAILURE
;
147 if (PR_GetOpenFileInfo(mCacheFD
, &fileInfo
) != PR_SUCCESS
) {
148 return NS_ERROR_FAILURE
;
150 if (PR_Seek64(mCacheFD
, 0, PR_SEEK_SET
) == -1) {
151 return NS_ERROR_FAILURE
;
153 uint32_t fileSize
= fileInfo
.size
;
155 auto data
= MakeUnique
<char[]>(fileSize
);
157 return NS_ERROR_OUT_OF_MEMORY
;
160 uint32_t actual
= PR_Read(mCacheFD
, data
.get(), fileSize
);
161 if (actual
!= fileSize
) {
162 return NS_ERROR_FAILURE
;
165 nsPrimitiveHelpers::CreatePrimitiveForData(mFlavor
, data
.get(), fileSize
,
170 //-------------------------------------------------------------------------
172 // Transferable constructor
174 //-------------------------------------------------------------------------
175 nsTransferable::nsTransferable()
176 : mPrivateData(false),
177 mContentPolicyType(nsIContentPolicy::TYPE_OTHER
)
185 //-------------------------------------------------------------------------
187 // Transferable destructor
189 //-------------------------------------------------------------------------
190 nsTransferable::~nsTransferable() = default;
193 nsTransferable::Init(nsILoadContext
* aContext
) {
194 MOZ_ASSERT(!mInitialized
);
197 mPrivateData
= aContext
->UsePrivateBrowsing();
199 // without aContext here to provide PrivateBrowsing information, we defer to
200 // the active configured setting
201 mPrivateData
= StaticPrefs::browser_privatebrowsing_autostart();
210 // GetTransferDataFlavors
212 // Returns a copy of the internal list of flavors. This does NOT take into
213 // account any converter that may be registered.
215 void nsTransferable::GetTransferDataFlavors(nsTArray
<nsCString
>& aFlavors
) {
216 MOZ_ASSERT(mInitialized
);
218 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
219 DataStruct
& data
= mDataArray
.ElementAt(i
);
220 aFlavors
.AppendElement(data
.GetFlavor());
224 Maybe
<size_t> nsTransferable::FindDataFlavor(const char* aFlavor
) {
225 nsDependentCString
flavor(aFlavor
);
227 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
228 if (mDataArray
[i
].GetFlavor().Equals(flavor
)) {
239 // Returns the data of the requested flavor, obtained from either having the
240 // data on hand or using a converter to get it. The data is wrapped in a
241 // nsISupports primitive so that it is accessible from JS.
244 nsTransferable::GetTransferData(const char* aFlavor
, nsISupports
** aData
) {
245 MOZ_ASSERT(mInitialized
);
251 // First look and see if the data is present in one of the intrinsic flavors.
252 if (Maybe
<size_t> index
= FindDataFlavor(aFlavor
)) {
253 nsCOMPtr
<nsISupports
> dataBytes
;
254 mDataArray
[index
.value()].GetData(getter_AddRefs(dataBytes
));
256 // Do we have a (lazy) data provider?
257 if (nsCOMPtr
<nsIFlavorDataProvider
> dataProvider
=
258 do_QueryInterface(dataBytes
)) {
260 dataProvider
->GetFlavorData(this, aFlavor
, getter_AddRefs(dataBytes
));
263 // The provider failed, fall into the converter code below.
268 dataBytes
.forget(aData
);
275 // If not, try using a format converter to get the requested flavor.
277 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
278 DataStruct
& data
= mDataArray
.ElementAt(i
);
279 bool canConvert
= false;
280 mFormatConv
->CanConvert(data
.GetFlavor().get(), aFlavor
, &canConvert
);
282 nsCOMPtr
<nsISupports
> dataBytes
;
283 data
.GetData(getter_AddRefs(dataBytes
));
285 // Do we have a (lazy) data provider?
286 if (nsCOMPtr
<nsIFlavorDataProvider
> dataProvider
=
287 do_QueryInterface(dataBytes
)) {
288 rv
= dataProvider
->GetFlavorData(this, aFlavor
,
289 getter_AddRefs(dataBytes
));
296 return mFormatConv
->Convert(data
.GetFlavor().get(), dataBytes
, aFlavor
,
302 return NS_ERROR_FAILURE
;
306 // GetAnyTransferData
308 // Returns the data of the first flavor found. Caller is responsible for
309 // deleting the flavor string.
312 nsTransferable::GetAnyTransferData(nsACString
& aFlavor
, nsISupports
** aData
) {
313 MOZ_ASSERT(mInitialized
);
315 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
316 DataStruct
& data
= mDataArray
.ElementAt(i
);
317 if (data
.IsDataAvailable()) {
318 aFlavor
.Assign(data
.GetFlavor());
324 return NS_ERROR_FAILURE
;
333 nsTransferable::SetTransferData(const char* aFlavor
, nsISupports
* aData
) {
334 MOZ_ASSERT(mInitialized
);
336 // first check our intrinsic flavors to see if one has been registered.
337 if (Maybe
<size_t> index
= FindDataFlavor(aFlavor
)) {
338 DataStruct
& data
= mDataArray
.ElementAt(index
.value());
339 data
.SetData(aData
, mPrivateData
);
343 // if not, try using a format converter to find a flavor to put the data in
345 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
346 DataStruct
& data
= mDataArray
.ElementAt(i
);
347 bool canConvert
= false;
348 mFormatConv
->CanConvert(aFlavor
, data
.GetFlavor().get(), &canConvert
);
351 nsCOMPtr
<nsISupports
> ConvertedData
;
352 mFormatConv
->Convert(aFlavor
, aData
, data
.GetFlavor().get(),
353 getter_AddRefs(ConvertedData
));
354 data
.SetData(ConvertedData
, mPrivateData
);
360 // Can't set data neither directly nor through converter. Just add this flavor
362 if (NS_SUCCEEDED(AddDataFlavor(aFlavor
))) {
363 return SetTransferData(aFlavor
, aData
);
366 return NS_ERROR_FAILURE
;
372 // Adds a data flavor to our list with no data. Error if it already exists.
375 nsTransferable::AddDataFlavor(const char* aDataFlavor
) {
376 MOZ_ASSERT(mInitialized
);
378 if (FindDataFlavor(aDataFlavor
).isSome()) {
379 return NS_ERROR_FAILURE
;
382 // Create a new "slot" for the data
383 mDataArray
.AppendElement(DataStruct(aDataFlavor
));
390 // Removes a data flavor (and causes the data to be destroyed). Error if
391 // the requested flavor is not present.
394 nsTransferable::RemoveDataFlavor(const char* aDataFlavor
) {
395 MOZ_ASSERT(mInitialized
);
397 if (Maybe
<size_t> index
= FindDataFlavor(aDataFlavor
)) {
398 mDataArray
.RemoveElementAt(index
.value());
402 return NS_ERROR_FAILURE
;
406 nsTransferable::SetConverter(nsIFormatConverter
* aConverter
) {
407 MOZ_ASSERT(mInitialized
);
409 mFormatConv
= aConverter
;
414 nsTransferable::GetConverter(nsIFormatConverter
** aConverter
) {
415 MOZ_ASSERT(mInitialized
);
417 nsCOMPtr
<nsIFormatConverter
> converter
= mFormatConv
;
418 converter
.forget(aConverter
);
423 // FlavorsTransferableCanImport
425 // Computes a list of flavors that the transferable can accept into it, either
426 // through intrinsic knowledge or input data converters.
429 nsTransferable::FlavorsTransferableCanImport(nsTArray
<nsCString
>& aFlavors
) {
430 MOZ_ASSERT(mInitialized
);
432 // Get the flavor list, and on to the end of it, append the list of flavors we
433 // can also get to through a converter. This is so that we can just walk the
434 // list in one go, looking for the desired flavor.
435 GetTransferDataFlavors(aFlavors
);
438 nsTArray
<nsCString
> convertedList
;
439 mFormatConv
->GetInputDataFlavors(convertedList
);
441 for (uint32_t i
= 0; i
< convertedList
.Length(); ++i
) {
442 nsCString
& flavorStr
= convertedList
[i
];
444 // Don't append if already in intrinsic list
445 if (!aFlavors
.Contains(flavorStr
)) {
446 aFlavors
.AppendElement(flavorStr
);
455 // FlavorsTransferableCanExport
457 // Computes a list of flavors that the transferable can export, either through
458 // intrinsic knowledge or output data converters.
461 nsTransferable::FlavorsTransferableCanExport(nsTArray
<nsCString
>& aFlavors
) {
462 MOZ_ASSERT(mInitialized
);
464 // Get the flavor list, and on to the end of it, append the list of flavors we
465 // can also get to through a converter. This is so that we can just walk the
466 // list in one go, looking for the desired flavor.
467 GetTransferDataFlavors(aFlavors
);
470 nsTArray
<nsCString
> convertedList
;
471 mFormatConv
->GetOutputDataFlavors(convertedList
);
473 for (uint32_t i
= 0; i
< convertedList
.Length(); ++i
) {
474 nsCString
& flavorStr
= convertedList
[i
];
476 // Don't append if already in intrinsic list
477 if (!aFlavors
.Contains(flavorStr
)) {
478 aFlavors
.AppendElement(flavorStr
);
486 bool nsTransferable::GetIsPrivateData() {
487 MOZ_ASSERT(mInitialized
);
492 void nsTransferable::SetIsPrivateData(bool aIsPrivateData
) {
493 MOZ_ASSERT(mInitialized
);
495 mPrivateData
= aIsPrivateData
;
498 nsIPrincipal
* nsTransferable::GetRequestingPrincipal() {
499 MOZ_ASSERT(mInitialized
);
501 return mRequestingPrincipal
;
504 void nsTransferable::SetRequestingPrincipal(
505 nsIPrincipal
* aRequestingPrincipal
) {
506 MOZ_ASSERT(mInitialized
);
508 mRequestingPrincipal
= aRequestingPrincipal
;
511 nsContentPolicyType
nsTransferable::GetContentPolicyType() {
512 MOZ_ASSERT(mInitialized
);
514 return mContentPolicyType
;
517 void nsTransferable::SetContentPolicyType(
518 nsContentPolicyType aContentPolicyType
) {
519 MOZ_ASSERT(mInitialized
);
521 mContentPolicyType
= aContentPolicyType
;
524 nsICookieJarSettings
* nsTransferable::GetCookieJarSettings() {
525 MOZ_ASSERT(mInitialized
);
527 return mCookieJarSettings
;
530 void nsTransferable::SetCookieJarSettings(
531 nsICookieJarSettings
* aCookieJarSettings
) {
532 MOZ_ASSERT(mInitialized
);
534 mCookieJarSettings
= aCookieJarSettings
;
537 nsIReferrerInfo
* nsTransferable::GetReferrerInfo() {
538 MOZ_ASSERT(mInitialized
);
539 return mReferrerInfo
;
542 void nsTransferable::SetReferrerInfo(nsIReferrerInfo
* aReferrerInfo
) {
543 MOZ_ASSERT(mInitialized
);
544 mReferrerInfo
= aReferrerInfo
;