widget/xpwidgets/nsTransferable.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
child 3
141e0f1194b1
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 void
    59 DataStruct::SetData ( nsISupports* aData, uint32_t aDataLen )
    60 {
    61 #if 0  // Remove unnecessary disk caching to accommodate https://www.torproject.org/projects/torbrowser/design/#disk-avoidance
    62   // Now, check to see if we consider the data to be "too large"
    63   if (aDataLen > kLargeDatasetSize) {
    64     // if so, cache it to disk instead of memory
    65     if ( NS_SUCCEEDED(WriteCache(aData, aDataLen)) )
    66       return;
    67     else
    68 			NS_WARNING("Oh no, couldn't write data to the cache file");   
    69   } 
    70 #endif  // #if 0
    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   for (i = 0; i < mDataArray.Length(); ++i) {
   404     DataStruct& data = mDataArray.ElementAt(i);
   405     if ( data.GetFlavor().Equals(aFlavor) ) {
   406       data.SetData ( aData, aDataLen );
   407       return NS_OK;
   408     }
   409   }
   411   // if not, try using a format converter to find a flavor to put the data in
   412   if ( mFormatConv ) {
   413     for (i = 0; i < mDataArray.Length(); ++i) {
   414       DataStruct& data = mDataArray.ElementAt(i);
   415       bool canConvert = false;
   416       mFormatConv->CanConvert(aFlavor, data.GetFlavor().get(), &canConvert);
   418       if ( canConvert ) {
   419         nsCOMPtr<nsISupports> ConvertedData;
   420         uint32_t ConvertedLen;
   421         mFormatConv->Convert(aFlavor, aData, aDataLen, data.GetFlavor().get(), getter_AddRefs(ConvertedData), &ConvertedLen);
   422         data.SetData(ConvertedData, ConvertedLen);
   423         return NS_OK;
   424       }
   425     }
   426   }
   428   // Can't set data neither directly nor through converter. Just add this flavor and try again
   429   nsresult result = NS_ERROR_FAILURE;
   430   if ( NS_SUCCEEDED(AddDataFlavor(aFlavor)) )
   431     result = SetTransferData (aFlavor, aData, aDataLen);
   433   return result;
   434 }
   437 //
   438 // AddDataFlavor
   439 //
   440 // Adds a data flavor to our list with no data. Error if it already exists.
   441 // 
   442 NS_IMETHODIMP
   443 nsTransferable::AddDataFlavor(const char *aDataFlavor)
   444 {
   445   MOZ_ASSERT(mInitialized);
   447   if (GetDataForFlavor (mDataArray, aDataFlavor) != mDataArray.NoIndex)
   448     return NS_ERROR_FAILURE;
   450   // Create a new "slot" for the data
   451   mDataArray.AppendElement(DataStruct ( aDataFlavor ));
   453   return NS_OK;
   454 }
   457 //
   458 // RemoveDataFlavor
   459 //
   460 // Removes a data flavor (and causes the data to be destroyed). Error if
   461 // the requested flavor is not present.
   462 //
   463 NS_IMETHODIMP
   464 nsTransferable::RemoveDataFlavor(const char *aDataFlavor)
   465 {
   466   MOZ_ASSERT(mInitialized);
   468   uint32_t idx;
   469   if ((idx = GetDataForFlavor(mDataArray, aDataFlavor)) != mDataArray.NoIndex) {
   470     mDataArray.RemoveElementAt (idx);
   471     return NS_OK;
   472   }
   473   return NS_ERROR_FAILURE;
   474 }
   477 /**
   478   * 
   479   *
   480   */
   481 NS_IMETHODIMP
   482 nsTransferable::IsLargeDataSet(bool *_retval)
   483 {
   484   MOZ_ASSERT(mInitialized);
   486   NS_ENSURE_ARG_POINTER(_retval);
   487   *_retval = false;
   488   return NS_OK;
   489 }
   492 /**
   493   * 
   494   *
   495   */
   496 NS_IMETHODIMP nsTransferable::SetConverter(nsIFormatConverter * aConverter)
   497 {
   498   MOZ_ASSERT(mInitialized);
   500   mFormatConv = aConverter;
   501   return NS_OK;
   502 }
   505 /**
   506   * 
   507   *
   508   */
   509 NS_IMETHODIMP nsTransferable::GetConverter(nsIFormatConverter * *aConverter)
   510 {
   511   MOZ_ASSERT(mInitialized);
   513   NS_ENSURE_ARG_POINTER(aConverter);
   514   *aConverter = mFormatConv;
   515   NS_IF_ADDREF(*aConverter);
   516   return NS_OK;
   517 }
   520 //
   521 // FlavorsTransferableCanImport
   522 //
   523 // Computes a list of flavors that the transferable can accept into it, either through
   524 // intrinsic knowledge or input data converters.
   525 //
   526 NS_IMETHODIMP
   527 nsTransferable::FlavorsTransferableCanImport(nsISupportsArray **_retval)
   528 {
   529   MOZ_ASSERT(mInitialized);
   531   NS_ENSURE_ARG_POINTER(_retval);
   533   // Get the flavor list, and on to the end of it, append the list of flavors we
   534   // can also get to through a converter. This is so that we can just walk the list
   535   // in one go, looking for the desired flavor.
   536   GetTransferDataFlavors(_retval);                        // addrefs
   537   nsCOMPtr<nsIFormatConverter> converter;
   538   GetConverter(getter_AddRefs(converter));
   539   if ( converter ) {
   540     nsCOMPtr<nsISupportsArray> convertedList;
   541     converter->GetInputDataFlavors(getter_AddRefs(convertedList));
   543     if ( convertedList ) {
   544       uint32_t importListLen;
   545       convertedList->Count(&importListLen);
   547       for ( uint32_t i=0; i < importListLen; ++i ) {
   548         nsCOMPtr<nsISupports> genericFlavor;
   549         convertedList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
   551         nsCOMPtr<nsISupportsCString> flavorWrapper ( do_QueryInterface (genericFlavor) );
   552         nsAutoCString flavorStr;
   553         flavorWrapper->GetData( flavorStr );
   555         if (GetDataForFlavor (mDataArray, flavorStr.get())
   556             == mDataArray.NoIndex) // Don't append if already in intrinsic list
   557           (*_retval)->AppendElement (genericFlavor);
   558       } // foreach flavor that can be converted to
   559     }
   560   } // if a converter exists
   562   return NS_OK;  
   563 } // FlavorsTransferableCanImport
   566 //
   567 // FlavorsTransferableCanExport
   568 //
   569 // Computes a list of flavors that the transferable can export, either through
   570 // intrinsic knowledge or output data converters.
   571 //
   572 NS_IMETHODIMP
   573 nsTransferable::FlavorsTransferableCanExport(nsISupportsArray **_retval)
   574 {
   575   MOZ_ASSERT(mInitialized);
   577   NS_ENSURE_ARG_POINTER(_retval);
   579   // Get the flavor list, and on to the end of it, append the list of flavors we
   580   // can also get to through a converter. This is so that we can just walk the list
   581   // in one go, looking for the desired flavor.
   582   GetTransferDataFlavors(_retval);  // addrefs
   583   nsCOMPtr<nsIFormatConverter> converter;
   584   GetConverter(getter_AddRefs(converter));
   585   if ( converter ) {
   586     nsCOMPtr<nsISupportsArray> convertedList;
   587     converter->GetOutputDataFlavors(getter_AddRefs(convertedList));
   589     if ( convertedList ) {
   590       uint32_t importListLen;
   591       convertedList->Count(&importListLen);
   593       for ( uint32_t i=0; i < importListLen; ++i ) {
   594         nsCOMPtr<nsISupports> genericFlavor;
   595         convertedList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
   597         nsCOMPtr<nsISupportsCString> flavorWrapper ( do_QueryInterface (genericFlavor) );
   598         nsAutoCString flavorStr;
   599         flavorWrapper->GetData( flavorStr );
   601         if (GetDataForFlavor (mDataArray, flavorStr.get())
   602             == mDataArray.NoIndex) // Don't append if already in intrinsic list
   603           (*_retval)->AppendElement (genericFlavor);
   604       } // foreach flavor that can be converted to
   605     }
   606   } // if a converter exists
   608   return NS_OK;
   609 } // FlavorsTransferableCanExport
   611 NS_IMETHODIMP
   612 nsTransferable::GetIsPrivateData(bool *aIsPrivateData)
   613 {
   614   MOZ_ASSERT(mInitialized);
   616   NS_ENSURE_ARG_POINTER(aIsPrivateData);
   618   *aIsPrivateData = mPrivateData;
   620   return NS_OK;
   621 }
   623 NS_IMETHODIMP
   624 nsTransferable::SetIsPrivateData(bool aIsPrivateData)
   625 {
   626   MOZ_ASSERT(mInitialized);
   628   mPrivateData = aIsPrivateData;
   630   return NS_OK;
   631 }

mercurial