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 void DataStruct::ClearData() {
121 //-------------------------------------------------------------------------
122 nsresult
DataStruct::WriteCache(void* aData
, uint32_t aDataLen
) {
123 MOZ_ASSERT(aData
&& aDataLen
);
124 MOZ_ASSERT(aDataLen
<= uint32_t(std::numeric_limits
<int32_t>::max()),
125 "too large size for PR_Write");
129 rv
= NS_OpenAnonymousTemporaryFile(&mCacheFD
);
131 return NS_ERROR_FAILURE
;
133 } else if (PR_Seek64(mCacheFD
, 0, PR_SEEK_SET
) == -1) {
134 return NS_ERROR_FAILURE
;
137 // Write out the contents of the clipboard to the file.
138 int32_t written
= PR_Write(mCacheFD
, aData
, aDataLen
);
139 if (written
== int32_t(aDataLen
)) {
145 return NS_ERROR_FAILURE
;
148 //-------------------------------------------------------------------------
149 nsresult
DataStruct::ReadCache(nsISupports
** aData
) {
151 return NS_ERROR_FAILURE
;
155 if (PR_GetOpenFileInfo(mCacheFD
, &fileInfo
) != PR_SUCCESS
) {
156 return NS_ERROR_FAILURE
;
158 if (PR_Seek64(mCacheFD
, 0, PR_SEEK_SET
) == -1) {
159 return NS_ERROR_FAILURE
;
161 uint32_t fileSize
= fileInfo
.size
;
163 auto data
= MakeUnique
<char[]>(fileSize
);
165 return NS_ERROR_OUT_OF_MEMORY
;
168 uint32_t actual
= PR_Read(mCacheFD
, data
.get(), fileSize
);
169 if (actual
!= fileSize
) {
170 return NS_ERROR_FAILURE
;
173 nsPrimitiveHelpers::CreatePrimitiveForData(mFlavor
, data
.get(), fileSize
,
178 //-------------------------------------------------------------------------
180 // Transferable constructor
182 //-------------------------------------------------------------------------
183 nsTransferable::nsTransferable()
184 : mPrivateData(false),
185 mContentPolicyType(nsIContentPolicy::TYPE_OTHER
)
193 //-------------------------------------------------------------------------
195 // Transferable destructor
197 //-------------------------------------------------------------------------
198 nsTransferable::~nsTransferable() = default;
201 nsTransferable::Init(nsILoadContext
* aContext
) {
202 MOZ_ASSERT(!mInitialized
);
205 mPrivateData
= aContext
->UsePrivateBrowsing();
207 // without aContext here to provide PrivateBrowsing information, we defer to
208 // the active configured setting
209 mPrivateData
= StaticPrefs::browser_privatebrowsing_autostart();
218 // GetTransferDataFlavors
220 // Returns a copy of the internal list of flavors. This does NOT take into
221 // account any converter that may be registered.
223 void nsTransferable::GetTransferDataFlavors(nsTArray
<nsCString
>& aFlavors
) {
224 MOZ_ASSERT(mInitialized
);
226 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
227 DataStruct
& data
= mDataArray
.ElementAt(i
);
228 aFlavors
.AppendElement(data
.GetFlavor());
232 Maybe
<size_t> nsTransferable::FindDataFlavor(const char* aFlavor
) {
233 nsDependentCString
flavor(aFlavor
);
235 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
236 if (mDataArray
[i
].GetFlavor().Equals(flavor
)) {
247 // Returns the data of the requested flavor, obtained from either having the
248 // data on hand or using a converter to get it. The data is wrapped in a
249 // nsISupports primitive so that it is accessible from JS.
252 nsTransferable::GetTransferData(const char* aFlavor
, nsISupports
** aData
) {
253 MOZ_ASSERT(mInitialized
);
259 // First look and see if the data is present in one of the intrinsic flavors.
260 if (Maybe
<size_t> index
= FindDataFlavor(aFlavor
)) {
261 nsCOMPtr
<nsISupports
> dataBytes
;
262 mDataArray
[index
.value()].GetData(getter_AddRefs(dataBytes
));
264 // Do we have a (lazy) data provider?
265 if (nsCOMPtr
<nsIFlavorDataProvider
> dataProvider
=
266 do_QueryInterface(dataBytes
)) {
268 dataProvider
->GetFlavorData(this, aFlavor
, getter_AddRefs(dataBytes
));
271 // The provider failed, fall into the converter code below.
276 dataBytes
.forget(aData
);
283 // If not, try using a format converter to get the requested flavor.
285 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
286 DataStruct
& data
= mDataArray
.ElementAt(i
);
287 bool canConvert
= false;
288 mFormatConv
->CanConvert(data
.GetFlavor().get(), aFlavor
, &canConvert
);
290 nsCOMPtr
<nsISupports
> dataBytes
;
291 data
.GetData(getter_AddRefs(dataBytes
));
293 // Do we have a (lazy) data provider?
294 if (nsCOMPtr
<nsIFlavorDataProvider
> dataProvider
=
295 do_QueryInterface(dataBytes
)) {
296 rv
= dataProvider
->GetFlavorData(this, aFlavor
,
297 getter_AddRefs(dataBytes
));
304 return mFormatConv
->Convert(data
.GetFlavor().get(), dataBytes
, aFlavor
,
310 return NS_ERROR_FAILURE
;
314 // GetAnyTransferData
316 // Returns the data of the first flavor found. Caller is responsible for
317 // deleting the flavor string.
320 nsTransferable::GetAnyTransferData(nsACString
& aFlavor
, nsISupports
** aData
) {
321 MOZ_ASSERT(mInitialized
);
323 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
324 DataStruct
& data
= mDataArray
.ElementAt(i
);
325 if (data
.IsDataAvailable()) {
326 aFlavor
.Assign(data
.GetFlavor());
332 return NS_ERROR_FAILURE
;
341 nsTransferable::SetTransferData(const char* aFlavor
, nsISupports
* aData
) {
342 MOZ_ASSERT(mInitialized
);
344 // first check our intrinsic flavors to see if one has been registered.
345 if (Maybe
<size_t> index
= FindDataFlavor(aFlavor
)) {
346 DataStruct
& data
= mDataArray
.ElementAt(index
.value());
347 data
.SetData(aData
, mPrivateData
);
351 // if not, try using a format converter to find a flavor to put the data in
353 for (size_t i
= 0; i
< mDataArray
.Length(); ++i
) {
354 DataStruct
& data
= mDataArray
.ElementAt(i
);
355 bool canConvert
= false;
356 mFormatConv
->CanConvert(aFlavor
, data
.GetFlavor().get(), &canConvert
);
359 nsCOMPtr
<nsISupports
> ConvertedData
;
360 mFormatConv
->Convert(aFlavor
, aData
, data
.GetFlavor().get(),
361 getter_AddRefs(ConvertedData
));
362 data
.SetData(ConvertedData
, mPrivateData
);
368 // Can't set data neither directly nor through converter. Just add this flavor
370 if (NS_SUCCEEDED(AddDataFlavor(aFlavor
))) {
371 return SetTransferData(aFlavor
, aData
);
374 return NS_ERROR_FAILURE
;
378 nsTransferable::ClearAllData() {
379 for (auto& entry
: mDataArray
) {
388 // Adds a data flavor to our list with no data. Error if it already exists.
391 nsTransferable::AddDataFlavor(const char* aDataFlavor
) {
392 MOZ_ASSERT(mInitialized
);
394 if (FindDataFlavor(aDataFlavor
).isSome()) {
395 return NS_ERROR_FAILURE
;
398 // Create a new "slot" for the data
399 mDataArray
.AppendElement(DataStruct(aDataFlavor
));
406 // Removes a data flavor (and causes the data to be destroyed). Error if
407 // the requested flavor is not present.
410 nsTransferable::RemoveDataFlavor(const char* aDataFlavor
) {
411 MOZ_ASSERT(mInitialized
);
413 if (Maybe
<size_t> index
= FindDataFlavor(aDataFlavor
)) {
414 mDataArray
.RemoveElementAt(index
.value());
418 return NS_ERROR_FAILURE
;
422 nsTransferable::SetConverter(nsIFormatConverter
* aConverter
) {
423 MOZ_ASSERT(mInitialized
);
425 mFormatConv
= aConverter
;
430 nsTransferable::GetConverter(nsIFormatConverter
** aConverter
) {
431 MOZ_ASSERT(mInitialized
);
433 nsCOMPtr
<nsIFormatConverter
> converter
= mFormatConv
;
434 converter
.forget(aConverter
);
439 // FlavorsTransferableCanImport
441 // Computes a list of flavors that the transferable can accept into it, either
442 // through intrinsic knowledge or input data converters.
445 nsTransferable::FlavorsTransferableCanImport(nsTArray
<nsCString
>& aFlavors
) {
446 MOZ_ASSERT(mInitialized
);
448 // Get the flavor list, and on to the end of it, append the list of flavors we
449 // can also get to through a converter. This is so that we can just walk the
450 // list in one go, looking for the desired flavor.
451 GetTransferDataFlavors(aFlavors
);
454 nsTArray
<nsCString
> convertedList
;
455 mFormatConv
->GetInputDataFlavors(convertedList
);
457 for (uint32_t i
= 0; i
< convertedList
.Length(); ++i
) {
458 nsCString
& flavorStr
= convertedList
[i
];
460 // Don't append if already in intrinsic list
461 if (!aFlavors
.Contains(flavorStr
)) {
462 aFlavors
.AppendElement(flavorStr
);
471 // FlavorsTransferableCanExport
473 // Computes a list of flavors that the transferable can export, either through
474 // intrinsic knowledge or output data converters.
477 nsTransferable::FlavorsTransferableCanExport(nsTArray
<nsCString
>& aFlavors
) {
478 MOZ_ASSERT(mInitialized
);
480 // Get the flavor list, and on to the end of it, append the list of flavors we
481 // can also get to through a converter. This is so that we can just walk the
482 // list in one go, looking for the desired flavor.
483 GetTransferDataFlavors(aFlavors
);
486 nsTArray
<nsCString
> convertedList
;
487 mFormatConv
->GetOutputDataFlavors(convertedList
);
489 for (uint32_t i
= 0; i
< convertedList
.Length(); ++i
) {
490 nsCString
& flavorStr
= convertedList
[i
];
492 // Don't append if already in intrinsic list
493 if (!aFlavors
.Contains(flavorStr
)) {
494 aFlavors
.AppendElement(flavorStr
);
502 bool nsTransferable::GetIsPrivateData() {
503 MOZ_ASSERT(mInitialized
);
508 void nsTransferable::SetIsPrivateData(bool aIsPrivateData
) {
509 MOZ_ASSERT(mInitialized
);
511 mPrivateData
= aIsPrivateData
;
514 nsIPrincipal
* nsTransferable::GetRequestingPrincipal() {
515 MOZ_ASSERT(mInitialized
);
517 return mRequestingPrincipal
;
520 void nsTransferable::SetRequestingPrincipal(
521 nsIPrincipal
* aRequestingPrincipal
) {
522 MOZ_ASSERT(mInitialized
);
524 mRequestingPrincipal
= aRequestingPrincipal
;
527 nsContentPolicyType
nsTransferable::GetContentPolicyType() {
528 MOZ_ASSERT(mInitialized
);
530 return mContentPolicyType
;
533 void nsTransferable::SetContentPolicyType(
534 nsContentPolicyType aContentPolicyType
) {
535 MOZ_ASSERT(mInitialized
);
537 mContentPolicyType
= aContentPolicyType
;
540 nsICookieJarSettings
* nsTransferable::GetCookieJarSettings() {
541 MOZ_ASSERT(mInitialized
);
543 return mCookieJarSettings
;
546 void nsTransferable::SetCookieJarSettings(
547 nsICookieJarSettings
* aCookieJarSettings
) {
548 MOZ_ASSERT(mInitialized
);
550 mCookieJarSettings
= aCookieJarSettings
;
553 nsIReferrerInfo
* nsTransferable::GetReferrerInfo() {
554 MOZ_ASSERT(mInitialized
);
555 return mReferrerInfo
;
558 void nsTransferable::SetReferrerInfo(nsIReferrerInfo
* aReferrerInfo
) {
559 MOZ_ASSERT(mInitialized
);
560 mReferrerInfo
= aReferrerInfo
;