widget/xpwidgets/nsTransferable.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
parent 9
a63d609f5ebe
child 11
deefc01c0e14
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 Notes to self:
michael@0 8
michael@0 9 - at some point, strings will be accessible from JS, so we won't have to wrap
michael@0 10 flavors in an nsISupportsCString. Until then, we're kinda stuck with
michael@0 11 this crappy API of nsISupportsArrays.
michael@0 12
michael@0 13 */
michael@0 14
michael@0 15
michael@0 16 #include "nsTransferable.h"
michael@0 17 #include "nsString.h"
michael@0 18 #include "nsReadableUtils.h"
michael@0 19 #include "nsTArray.h"
michael@0 20 #include "nsIFormatConverter.h"
michael@0 21 #include "nsIComponentManager.h"
michael@0 22 #include "nsCOMPtr.h"
michael@0 23 #include "nsXPCOM.h"
michael@0 24 #include "nsISupportsPrimitives.h"
michael@0 25 #include "nsMemory.h"
michael@0 26 #include "nsPrimitiveHelpers.h"
michael@0 27 #include "nsXPIDLString.h"
michael@0 28 #include "nsDirectoryServiceDefs.h"
michael@0 29 #include "nsDirectoryService.h"
michael@0 30 #include "nsCRT.h"
michael@0 31 #include "nsNetUtil.h"
michael@0 32 #include "nsIOutputStream.h"
michael@0 33 #include "nsIInputStream.h"
michael@0 34 #include "nsIFile.h"
michael@0 35 #include "nsILoadContext.h"
michael@0 36 #include "nsAutoPtr.h"
michael@0 37
michael@0 38 NS_IMPL_ISUPPORTS(nsTransferable, nsITransferable)
michael@0 39
michael@0 40 uint32_t GetDataForFlavor (const nsTArray<DataStruct>& aArray,
michael@0 41 const char* aDataFlavor)
michael@0 42 {
michael@0 43 for (uint32_t i = 0 ; i < aArray.Length () ; ++i) {
michael@0 44 if (aArray[i].GetFlavor().Equals (aDataFlavor))
michael@0 45 return i;
michael@0 46 }
michael@0 47
michael@0 48 return aArray.NoIndex;
michael@0 49 }
michael@0 50
michael@0 51 //-------------------------------------------------------------------------
michael@0 52 DataStruct::~DataStruct()
michael@0 53 {
michael@0 54 if (mCacheFileName) free(mCacheFileName);
michael@0 55 }
michael@0 56
michael@0 57 //-------------------------------------------------------------------------
michael@10 58 // The SetData method is overloaded to indicate private browsing mode
michael@10 59 // while achieving some semblance of (private) interface compatibility.
michael@10 60 //-------------------------------------------------------------------------
michael@10 61 void
michael@10 62 DataStruct::SetData ( nsISupports* aData, uint32_t aDataLen, bool aIsPrivBrowsing )
michael@10 63 {
michael@10 64 // Now, check to see if we consider the data to be "too large"
michael@10 65 // as well as ensuring that private browsing mode is disabled
michael@10 66 if (aDataLen > kLargeDatasetSize && aIsPrivBrowsing == false) {
michael@10 67 // if so, cache it to disk instead of memory
michael@10 68 if ( NS_SUCCEEDED(WriteCache(aData, aDataLen)) )
michael@10 69 return;
michael@10 70 else
michael@10 71 NS_WARNING("Oh no, couldn't write data to the cache file");
michael@10 72 }
michael@10 73
michael@10 74 mData = aData;
michael@10 75 mDataLen = aDataLen;
michael@10 76 }
michael@10 77
michael@10 78
michael@10 79 //-------------------------------------------------------------------------
michael@0 80 void
michael@0 81 DataStruct::SetData ( nsISupports* aData, uint32_t aDataLen )
michael@0 82 {
michael@0 83 // Now, check to see if we consider the data to be "too large"
michael@9 84 if (aDataLen > kLargeDatasetSize) {
michael@0 85 // if so, cache it to disk instead of memory
michael@0 86 if ( NS_SUCCEEDED(WriteCache(aData, aDataLen)) )
michael@0 87 return;
michael@0 88 else
michael@0 89 NS_WARNING("Oh no, couldn't write data to the cache file");
michael@0 90 }
michael@0 91
michael@0 92 mData = aData;
michael@0 93 mDataLen = aDataLen;
michael@0 94 }
michael@0 95
michael@0 96
michael@0 97 //-------------------------------------------------------------------------
michael@0 98 void
michael@0 99 DataStruct::GetData ( nsISupports** aData, uint32_t *aDataLen )
michael@0 100 {
michael@0 101 // check here to see if the data is cached on disk
michael@0 102 if ( !mData && mCacheFileName ) {
michael@0 103 // if so, read it in and pass it back
michael@0 104 // ReadCache creates memory and copies the data into it.
michael@0 105 if ( NS_SUCCEEDED(ReadCache(aData, aDataLen)) )
michael@0 106 return;
michael@0 107 else {
michael@0 108 // oh shit, something went horribly wrong here.
michael@0 109 NS_WARNING("Oh no, couldn't read data in from the cache file");
michael@0 110 *aData = nullptr;
michael@0 111 *aDataLen = 0;
michael@0 112 return;
michael@0 113 }
michael@0 114 }
michael@0 115
michael@0 116 *aData = mData;
michael@0 117 if ( mData )
michael@0 118 NS_ADDREF(*aData);
michael@0 119 *aDataLen = mDataLen;
michael@0 120 }
michael@0 121
michael@0 122
michael@0 123 //-------------------------------------------------------------------------
michael@0 124 already_AddRefed<nsIFile>
michael@0 125 DataStruct::GetFileSpec(const char* aFileName)
michael@0 126 {
michael@0 127 nsCOMPtr<nsIFile> cacheFile;
michael@0 128 NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(cacheFile));
michael@0 129
michael@0 130 if (!cacheFile)
michael@0 131 return nullptr;
michael@0 132
michael@0 133 // if the param aFileName contains a name we should use that
michael@0 134 // because the file probably already exists
michael@0 135 // otherwise create a unique name
michael@0 136 if (!aFileName) {
michael@0 137 cacheFile->AppendNative(NS_LITERAL_CSTRING("clipboardcache"));
michael@0 138 cacheFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
michael@0 139 } else {
michael@0 140 cacheFile->AppendNative(nsDependentCString(aFileName));
michael@0 141 }
michael@0 142
michael@0 143 return cacheFile.forget();
michael@0 144 }
michael@0 145
michael@0 146
michael@0 147 //-------------------------------------------------------------------------
michael@0 148 nsresult
michael@0 149 DataStruct::WriteCache(nsISupports* aData, uint32_t aDataLen)
michael@0 150 {
michael@0 151 // Get a new path and file to the temp directory
michael@0 152 nsCOMPtr<nsIFile> cacheFile = GetFileSpec(mCacheFileName);
michael@0 153 if (cacheFile) {
michael@0 154 // remember the file name
michael@0 155 if (!mCacheFileName) {
michael@0 156 nsXPIDLCString fName;
michael@0 157 cacheFile->GetNativeLeafName(fName);
michael@0 158 mCacheFileName = strdup(fName);
michael@0 159 }
michael@0 160
michael@0 161 // write out the contents of the clipboard
michael@0 162 // to the file
michael@0 163 //uint32_t bytes;
michael@0 164 nsCOMPtr<nsIOutputStream> outStr;
michael@0 165
michael@0 166 NS_NewLocalFileOutputStream(getter_AddRefs(outStr),
michael@0 167 cacheFile);
michael@0 168
michael@0 169 if (!outStr) return NS_ERROR_FAILURE;
michael@0 170
michael@0 171 void* buff = nullptr;
michael@0 172 nsPrimitiveHelpers::CreateDataFromPrimitive ( mFlavor.get(), aData, &buff, aDataLen );
michael@0 173 if ( buff ) {
michael@0 174 uint32_t ignored;
michael@0 175 outStr->Write(reinterpret_cast<char*>(buff), aDataLen, &ignored);
michael@0 176 nsMemory::Free(buff);
michael@0 177 return NS_OK;
michael@0 178 }
michael@0 179 }
michael@0 180 return NS_ERROR_FAILURE;
michael@0 181 }
michael@0 182
michael@0 183
michael@0 184 //-------------------------------------------------------------------------
michael@0 185 nsresult
michael@0 186 DataStruct::ReadCache(nsISupports** aData, uint32_t* aDataLen)
michael@0 187 {
michael@0 188 // if we don't have a cache filename we are out of luck
michael@0 189 if (!mCacheFileName)
michael@0 190 return NS_ERROR_FAILURE;
michael@0 191
michael@0 192 // get the path and file name
michael@0 193 nsCOMPtr<nsIFile> cacheFile = GetFileSpec(mCacheFileName);
michael@0 194 bool exists;
michael@0 195 if ( cacheFile && NS_SUCCEEDED(cacheFile->Exists(&exists)) && exists ) {
michael@0 196 // get the size of the file
michael@0 197 int64_t fileSize;
michael@0 198 int64_t max32 = 0xFFFFFFFF;
michael@0 199 cacheFile->GetFileSize(&fileSize);
michael@0 200 if (fileSize > max32)
michael@0 201 return NS_ERROR_OUT_OF_MEMORY;
michael@0 202
michael@0 203 uint32_t size = uint32_t(fileSize);
michael@0 204 // create new memory for the large clipboard data
michael@0 205 nsAutoArrayPtr<char> data(new char[size]);
michael@0 206 if ( !data )
michael@0 207 return NS_ERROR_OUT_OF_MEMORY;
michael@0 208
michael@0 209 // now read it all in
michael@0 210 nsCOMPtr<nsIInputStream> inStr;
michael@0 211 NS_NewLocalFileInputStream( getter_AddRefs(inStr),
michael@0 212 cacheFile);
michael@0 213
michael@0 214 if (!cacheFile) return NS_ERROR_FAILURE;
michael@0 215
michael@0 216 nsresult rv = inStr->Read(data, fileSize, aDataLen);
michael@0 217
michael@0 218 // make sure we got all the data ok
michael@0 219 if (NS_SUCCEEDED(rv) && *aDataLen == size) {
michael@0 220 nsPrimitiveHelpers::CreatePrimitiveForData ( mFlavor.get(), data, fileSize, aData );
michael@0 221 return *aData ? NS_OK : NS_ERROR_FAILURE;
michael@0 222 }
michael@0 223
michael@0 224 // zero the return params
michael@0 225 *aData = nullptr;
michael@0 226 *aDataLen = 0;
michael@0 227 }
michael@0 228
michael@0 229 return NS_ERROR_FAILURE;
michael@0 230 }
michael@0 231
michael@0 232
michael@0 233 //-------------------------------------------------------------------------
michael@0 234 //
michael@0 235 // Transferable constructor
michael@0 236 //
michael@0 237 //-------------------------------------------------------------------------
michael@0 238 nsTransferable::nsTransferable()
michael@0 239 : mPrivateData(false)
michael@0 240 #ifdef DEBUG
michael@0 241 , mInitialized(false)
michael@0 242 #endif
michael@0 243 {
michael@0 244 }
michael@0 245
michael@0 246 //-------------------------------------------------------------------------
michael@0 247 //
michael@0 248 // Transferable destructor
michael@0 249 //
michael@0 250 //-------------------------------------------------------------------------
michael@0 251 nsTransferable::~nsTransferable()
michael@0 252 {
michael@0 253 }
michael@0 254
michael@0 255
michael@0 256 NS_IMETHODIMP
michael@0 257 nsTransferable::Init(nsILoadContext* aContext)
michael@0 258 {
michael@0 259 MOZ_ASSERT(!mInitialized);
michael@0 260
michael@0 261 if (aContext) {
michael@0 262 mPrivateData = aContext->UsePrivateBrowsing();
michael@0 263 }
michael@0 264 #ifdef DEBUG
michael@0 265 mInitialized = true;
michael@0 266 #endif
michael@0 267 return NS_OK;
michael@0 268 }
michael@0 269
michael@0 270 //
michael@0 271 // GetTransferDataFlavors
michael@0 272 //
michael@0 273 // Returns a copy of the internal list of flavors. This does NOT take into
michael@0 274 // account any converter that may be registered. This list consists of
michael@0 275 // nsISupportsCString objects so that the flavor list can be accessed from JS.
michael@0 276 //
michael@0 277 nsresult
michael@0 278 nsTransferable::GetTransferDataFlavors(nsISupportsArray ** aDataFlavorList)
michael@0 279 {
michael@0 280 MOZ_ASSERT(mInitialized);
michael@0 281
michael@0 282 nsresult rv = NS_NewISupportsArray ( aDataFlavorList );
michael@0 283 if (NS_FAILED(rv)) return rv;
michael@0 284
michael@0 285 for ( uint32_t i=0; i<mDataArray.Length(); ++i ) {
michael@0 286 DataStruct& data = mDataArray.ElementAt(i);
michael@0 287 nsCOMPtr<nsISupportsCString> flavorWrapper = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
michael@0 288 if ( flavorWrapper ) {
michael@0 289 flavorWrapper->SetData ( data.GetFlavor() );
michael@0 290 nsCOMPtr<nsISupports> genericWrapper ( do_QueryInterface(flavorWrapper) );
michael@0 291 (*aDataFlavorList)->AppendElement( genericWrapper );
michael@0 292 }
michael@0 293 }
michael@0 294
michael@0 295 return NS_OK;
michael@0 296 }
michael@0 297
michael@0 298
michael@0 299 //
michael@0 300 // GetTransferData
michael@0 301 //
michael@0 302 // Returns the data of the requested flavor, obtained from either having the data on hand or
michael@0 303 // using a converter to get it. The data is wrapped in a nsISupports primitive so that it is
michael@0 304 // accessible from JS.
michael@0 305 //
michael@0 306 NS_IMETHODIMP
michael@0 307 nsTransferable::GetTransferData(const char *aFlavor, nsISupports **aData, uint32_t *aDataLen)
michael@0 308 {
michael@0 309 MOZ_ASSERT(mInitialized);
michael@0 310
michael@0 311 NS_ENSURE_ARG_POINTER(aFlavor && aData && aDataLen);
michael@0 312
michael@0 313 nsresult rv = NS_OK;
michael@0 314 nsCOMPtr<nsISupports> savedData;
michael@0 315
michael@0 316 // first look and see if the data is present in one of the intrinsic flavors
michael@0 317 uint32_t i;
michael@0 318 for (i = 0; i < mDataArray.Length(); ++i ) {
michael@0 319 DataStruct& data = mDataArray.ElementAt(i);
michael@0 320 if ( data.GetFlavor().Equals(aFlavor) ) {
michael@0 321 nsCOMPtr<nsISupports> dataBytes;
michael@0 322 uint32_t len;
michael@0 323 data.GetData(getter_AddRefs(dataBytes), &len);
michael@0 324 if (len == kFlavorHasDataProvider && dataBytes) {
michael@0 325 // do we have a data provider?
michael@0 326 nsCOMPtr<nsIFlavorDataProvider> dataProvider = do_QueryInterface(dataBytes);
michael@0 327 if (dataProvider) {
michael@0 328 rv = dataProvider->GetFlavorData(this, aFlavor,
michael@0 329 getter_AddRefs(dataBytes), &len);
michael@0 330 if (NS_FAILED(rv))
michael@0 331 break; // the provider failed. fall into the converter code below.
michael@0 332 }
michael@0 333 }
michael@0 334 if (dataBytes && len > 0) { // XXXmats why is zero length not ok?
michael@0 335 *aDataLen = len;
michael@0 336 dataBytes.forget(aData);
michael@0 337 return NS_OK;
michael@0 338 }
michael@0 339 savedData = dataBytes; // return this if format converter fails
michael@0 340 break;
michael@0 341 }
michael@0 342 }
michael@0 343
michael@0 344 bool found = false;
michael@0 345
michael@0 346 // if not, try using a format converter to get the requested flavor
michael@0 347 if ( mFormatConv ) {
michael@0 348 for (i = 0; i < mDataArray.Length(); ++i) {
michael@0 349 DataStruct& data = mDataArray.ElementAt(i);
michael@0 350 bool canConvert = false;
michael@0 351 mFormatConv->CanConvert(data.GetFlavor().get(), aFlavor, &canConvert);
michael@0 352 if ( canConvert ) {
michael@0 353 nsCOMPtr<nsISupports> dataBytes;
michael@0 354 uint32_t len;
michael@0 355 data.GetData(getter_AddRefs(dataBytes), &len);
michael@0 356 if (len == kFlavorHasDataProvider && dataBytes) {
michael@0 357 // do we have a data provider?
michael@0 358 nsCOMPtr<nsIFlavorDataProvider> dataProvider = do_QueryInterface(dataBytes);
michael@0 359 if (dataProvider) {
michael@0 360 rv = dataProvider->GetFlavorData(this, aFlavor,
michael@0 361 getter_AddRefs(dataBytes), &len);
michael@0 362 if (NS_FAILED(rv))
michael@0 363 break; // give up
michael@0 364 }
michael@0 365 }
michael@0 366 mFormatConv->Convert(data.GetFlavor().get(), dataBytes, len, aFlavor, aData, aDataLen);
michael@0 367 found = true;
michael@0 368 break;
michael@0 369 }
michael@0 370 }
michael@0 371 }
michael@0 372
michael@0 373 // for backward compatibility
michael@0 374 if (!found) {
michael@0 375 savedData.forget(aData);
michael@0 376 *aDataLen = 0;
michael@0 377 }
michael@0 378
michael@0 379 return found ? NS_OK : NS_ERROR_FAILURE;
michael@0 380 }
michael@0 381
michael@0 382
michael@0 383 //
michael@0 384 // GetAnyTransferData
michael@0 385 //
michael@0 386 // Returns the data of the first flavor found. Caller is responsible for deleting the
michael@0 387 // flavor string.
michael@0 388 //
michael@0 389 NS_IMETHODIMP
michael@0 390 nsTransferable::GetAnyTransferData(char **aFlavor, nsISupports **aData, uint32_t *aDataLen)
michael@0 391 {
michael@0 392 MOZ_ASSERT(mInitialized);
michael@0 393
michael@0 394 NS_ENSURE_ARG_POINTER(aFlavor && aData && aDataLen);
michael@0 395
michael@0 396 for ( uint32_t i=0; i < mDataArray.Length(); ++i ) {
michael@0 397 DataStruct& data = mDataArray.ElementAt(i);
michael@0 398 if (data.IsDataAvailable()) {
michael@0 399 *aFlavor = ToNewCString(data.GetFlavor());
michael@0 400 data.GetData(aData, aDataLen);
michael@0 401 return NS_OK;
michael@0 402 }
michael@0 403 }
michael@0 404
michael@0 405 return NS_ERROR_FAILURE;
michael@0 406 }
michael@0 407
michael@0 408
michael@0 409 //
michael@0 410 // SetTransferData
michael@0 411 //
michael@0 412 //
michael@0 413 //
michael@0 414 NS_IMETHODIMP
michael@0 415 nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, uint32_t aDataLen)
michael@0 416 {
michael@0 417 MOZ_ASSERT(mInitialized);
michael@0 418
michael@0 419 NS_ENSURE_ARG(aFlavor);
michael@0 420
michael@0 421 // first check our intrinsic flavors to see if one has been registered.
michael@0 422 uint32_t i = 0;
michael@10 423 bool aIsPrivBrowsing = false;
michael@0 424 for (i = 0; i < mDataArray.Length(); ++i) {
michael@0 425 DataStruct& data = mDataArray.ElementAt(i);
michael@0 426 if ( data.GetFlavor().Equals(aFlavor) ) {
michael@10 427 if ( NS_SUCCEEDED(GetIsPrivateData(&aIsPrivBrowsing)) ) {
michael@10 428 data.SetData ( aData, aDataLen, aIsPrivBrowsing );
michael@10 429 return NS_OK;
michael@10 430 }
michael@10 431 else { // call to GetIsPrivateData() failed,
michael@10 432 return NS_ERROR_FAILURE; // we didn't SetData(), generic error
michael@10 433 }
michael@0 434 }
michael@0 435 }
michael@0 436
michael@0 437 // if not, try using a format converter to find a flavor to put the data in
michael@0 438 if ( mFormatConv ) {
michael@0 439 for (i = 0; i < mDataArray.Length(); ++i) {
michael@0 440 DataStruct& data = mDataArray.ElementAt(i);
michael@0 441 bool canConvert = false;
michael@0 442 mFormatConv->CanConvert(aFlavor, data.GetFlavor().get(), &canConvert);
michael@0 443
michael@0 444 if ( canConvert ) {
michael@0 445 nsCOMPtr<nsISupports> ConvertedData;
michael@0 446 uint32_t ConvertedLen;
michael@0 447 mFormatConv->Convert(aFlavor, aData, aDataLen, data.GetFlavor().get(), getter_AddRefs(ConvertedData), &ConvertedLen);
michael@0 448 data.SetData(ConvertedData, ConvertedLen);
michael@0 449 return NS_OK;
michael@0 450 }
michael@0 451 }
michael@0 452 }
michael@0 453
michael@0 454 // Can't set data neither directly nor through converter. Just add this flavor and try again
michael@0 455 nsresult result = NS_ERROR_FAILURE;
michael@0 456 if ( NS_SUCCEEDED(AddDataFlavor(aFlavor)) )
michael@0 457 result = SetTransferData (aFlavor, aData, aDataLen);
michael@0 458
michael@0 459 return result;
michael@0 460 }
michael@0 461
michael@0 462
michael@0 463 //
michael@0 464 // AddDataFlavor
michael@0 465 //
michael@0 466 // Adds a data flavor to our list with no data. Error if it already exists.
michael@0 467 //
michael@0 468 NS_IMETHODIMP
michael@0 469 nsTransferable::AddDataFlavor(const char *aDataFlavor)
michael@0 470 {
michael@0 471 MOZ_ASSERT(mInitialized);
michael@0 472
michael@0 473 if (GetDataForFlavor (mDataArray, aDataFlavor) != mDataArray.NoIndex)
michael@0 474 return NS_ERROR_FAILURE;
michael@0 475
michael@0 476 // Create a new "slot" for the data
michael@0 477 mDataArray.AppendElement(DataStruct ( aDataFlavor ));
michael@0 478
michael@0 479 return NS_OK;
michael@0 480 }
michael@0 481
michael@0 482
michael@0 483 //
michael@0 484 // RemoveDataFlavor
michael@0 485 //
michael@0 486 // Removes a data flavor (and causes the data to be destroyed). Error if
michael@0 487 // the requested flavor is not present.
michael@0 488 //
michael@0 489 NS_IMETHODIMP
michael@0 490 nsTransferable::RemoveDataFlavor(const char *aDataFlavor)
michael@0 491 {
michael@0 492 MOZ_ASSERT(mInitialized);
michael@0 493
michael@0 494 uint32_t idx;
michael@0 495 if ((idx = GetDataForFlavor(mDataArray, aDataFlavor)) != mDataArray.NoIndex) {
michael@0 496 mDataArray.RemoveElementAt (idx);
michael@0 497 return NS_OK;
michael@0 498 }
michael@0 499 return NS_ERROR_FAILURE;
michael@0 500 }
michael@0 501
michael@0 502
michael@0 503 /**
michael@0 504 *
michael@0 505 *
michael@0 506 */
michael@0 507 NS_IMETHODIMP
michael@0 508 nsTransferable::IsLargeDataSet(bool *_retval)
michael@0 509 {
michael@0 510 MOZ_ASSERT(mInitialized);
michael@0 511
michael@0 512 NS_ENSURE_ARG_POINTER(_retval);
michael@0 513 *_retval = false;
michael@0 514 return NS_OK;
michael@0 515 }
michael@0 516
michael@0 517
michael@0 518 /**
michael@0 519 *
michael@0 520 *
michael@0 521 */
michael@0 522 NS_IMETHODIMP nsTransferable::SetConverter(nsIFormatConverter * aConverter)
michael@0 523 {
michael@0 524 MOZ_ASSERT(mInitialized);
michael@0 525
michael@0 526 mFormatConv = aConverter;
michael@0 527 return NS_OK;
michael@0 528 }
michael@0 529
michael@0 530
michael@0 531 /**
michael@0 532 *
michael@0 533 *
michael@0 534 */
michael@0 535 NS_IMETHODIMP nsTransferable::GetConverter(nsIFormatConverter * *aConverter)
michael@0 536 {
michael@0 537 MOZ_ASSERT(mInitialized);
michael@0 538
michael@0 539 NS_ENSURE_ARG_POINTER(aConverter);
michael@0 540 *aConverter = mFormatConv;
michael@0 541 NS_IF_ADDREF(*aConverter);
michael@0 542 return NS_OK;
michael@0 543 }
michael@0 544
michael@0 545
michael@0 546 //
michael@0 547 // FlavorsTransferableCanImport
michael@0 548 //
michael@0 549 // Computes a list of flavors that the transferable can accept into it, either through
michael@0 550 // intrinsic knowledge or input data converters.
michael@0 551 //
michael@0 552 NS_IMETHODIMP
michael@0 553 nsTransferable::FlavorsTransferableCanImport(nsISupportsArray **_retval)
michael@0 554 {
michael@0 555 MOZ_ASSERT(mInitialized);
michael@0 556
michael@0 557 NS_ENSURE_ARG_POINTER(_retval);
michael@0 558
michael@0 559 // Get the flavor list, and on to the end of it, append the list of flavors we
michael@0 560 // can also get to through a converter. This is so that we can just walk the list
michael@0 561 // in one go, looking for the desired flavor.
michael@0 562 GetTransferDataFlavors(_retval); // addrefs
michael@0 563 nsCOMPtr<nsIFormatConverter> converter;
michael@0 564 GetConverter(getter_AddRefs(converter));
michael@0 565 if ( converter ) {
michael@0 566 nsCOMPtr<nsISupportsArray> convertedList;
michael@0 567 converter->GetInputDataFlavors(getter_AddRefs(convertedList));
michael@0 568
michael@0 569 if ( convertedList ) {
michael@0 570 uint32_t importListLen;
michael@0 571 convertedList->Count(&importListLen);
michael@0 572
michael@0 573 for ( uint32_t i=0; i < importListLen; ++i ) {
michael@0 574 nsCOMPtr<nsISupports> genericFlavor;
michael@0 575 convertedList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
michael@0 576
michael@0 577 nsCOMPtr<nsISupportsCString> flavorWrapper ( do_QueryInterface (genericFlavor) );
michael@0 578 nsAutoCString flavorStr;
michael@0 579 flavorWrapper->GetData( flavorStr );
michael@0 580
michael@0 581 if (GetDataForFlavor (mDataArray, flavorStr.get())
michael@0 582 == mDataArray.NoIndex) // Don't append if already in intrinsic list
michael@0 583 (*_retval)->AppendElement (genericFlavor);
michael@0 584 } // foreach flavor that can be converted to
michael@0 585 }
michael@0 586 } // if a converter exists
michael@0 587
michael@0 588 return NS_OK;
michael@0 589 } // FlavorsTransferableCanImport
michael@0 590
michael@0 591
michael@0 592 //
michael@0 593 // FlavorsTransferableCanExport
michael@0 594 //
michael@0 595 // Computes a list of flavors that the transferable can export, either through
michael@0 596 // intrinsic knowledge or output data converters.
michael@0 597 //
michael@0 598 NS_IMETHODIMP
michael@0 599 nsTransferable::FlavorsTransferableCanExport(nsISupportsArray **_retval)
michael@0 600 {
michael@0 601 MOZ_ASSERT(mInitialized);
michael@0 602
michael@0 603 NS_ENSURE_ARG_POINTER(_retval);
michael@0 604
michael@0 605 // Get the flavor list, and on to the end of it, append the list of flavors we
michael@0 606 // can also get to through a converter. This is so that we can just walk the list
michael@0 607 // in one go, looking for the desired flavor.
michael@0 608 GetTransferDataFlavors(_retval); // addrefs
michael@0 609 nsCOMPtr<nsIFormatConverter> converter;
michael@0 610 GetConverter(getter_AddRefs(converter));
michael@0 611 if ( converter ) {
michael@0 612 nsCOMPtr<nsISupportsArray> convertedList;
michael@0 613 converter->GetOutputDataFlavors(getter_AddRefs(convertedList));
michael@0 614
michael@0 615 if ( convertedList ) {
michael@0 616 uint32_t importListLen;
michael@0 617 convertedList->Count(&importListLen);
michael@0 618
michael@0 619 for ( uint32_t i=0; i < importListLen; ++i ) {
michael@0 620 nsCOMPtr<nsISupports> genericFlavor;
michael@0 621 convertedList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
michael@0 622
michael@0 623 nsCOMPtr<nsISupportsCString> flavorWrapper ( do_QueryInterface (genericFlavor) );
michael@0 624 nsAutoCString flavorStr;
michael@0 625 flavorWrapper->GetData( flavorStr );
michael@0 626
michael@0 627 if (GetDataForFlavor (mDataArray, flavorStr.get())
michael@0 628 == mDataArray.NoIndex) // Don't append if already in intrinsic list
michael@0 629 (*_retval)->AppendElement (genericFlavor);
michael@0 630 } // foreach flavor that can be converted to
michael@0 631 }
michael@0 632 } // if a converter exists
michael@0 633
michael@0 634 return NS_OK;
michael@0 635 } // FlavorsTransferableCanExport
michael@0 636
michael@0 637 NS_IMETHODIMP
michael@0 638 nsTransferable::GetIsPrivateData(bool *aIsPrivateData)
michael@0 639 {
michael@0 640 MOZ_ASSERT(mInitialized);
michael@0 641
michael@0 642 NS_ENSURE_ARG_POINTER(aIsPrivateData);
michael@0 643
michael@0 644 *aIsPrivateData = mPrivateData;
michael@0 645
michael@0 646 return NS_OK;
michael@0 647 }
michael@0 648
michael@0 649 NS_IMETHODIMP
michael@0 650 nsTransferable::SetIsPrivateData(bool aIsPrivateData)
michael@0 651 {
michael@0 652 MOZ_ASSERT(mInitialized);
michael@0 653
michael@0 654 mPrivateData = aIsPrivateData;
michael@0 655
michael@0 656 return NS_OK;
michael@0 657 }
michael@0 658

mercurial