widget/xpwidgets/nsTransferable.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
parent 10
ac0c01689b40
child 12
7540298fafa1
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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

mercurial