widget/xpwidgets/nsTransferable.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
parent 0
6474c204b198
child 8
97036ab72558
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     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   // Now, check to see if we consider the data to be "too large"
    62   if (aDataLen > kLargeDatasetSize) {
    63     // if so, cache it to disk instead of memory
    64     if ( NS_SUCCEEDED(WriteCache(aData, aDataLen)) )
    65       return;
    66     else
    67 			NS_WARNING("Oh no, couldn't write data to the cache file");   
    68   } 
    70   mData    = aData;
    71   mDataLen = aDataLen;  
    72 }
    75 //-------------------------------------------------------------------------
    76 void
    77 DataStruct::GetData ( nsISupports** aData, uint32_t *aDataLen )
    78 {
    79   // check here to see if the data is cached on disk
    80   if ( !mData && mCacheFileName ) {
    81     // if so, read it in and pass it back
    82     // ReadCache creates memory and copies the data into it.
    83     if ( NS_SUCCEEDED(ReadCache(aData, aDataLen)) )
    84       return;
    85     else {
    86       // oh shit, something went horribly wrong here.
    87       NS_WARNING("Oh no, couldn't read data in from the cache file");
    88       *aData = nullptr;
    89       *aDataLen = 0;
    90       return;
    91     }
    92   }
    94   *aData = mData;
    95   if ( mData )
    96     NS_ADDREF(*aData); 
    97   *aDataLen = mDataLen;
    98 }
   101 //-------------------------------------------------------------------------
   102 already_AddRefed<nsIFile>
   103 DataStruct::GetFileSpec(const char* aFileName)
   104 {
   105   nsCOMPtr<nsIFile> cacheFile;
   106   NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(cacheFile));
   108   if (!cacheFile)
   109     return nullptr;
   111   // if the param aFileName contains a name we should use that
   112   // because the file probably already exists
   113   // otherwise create a unique name
   114   if (!aFileName) {
   115     cacheFile->AppendNative(NS_LITERAL_CSTRING("clipboardcache"));
   116     cacheFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
   117   } else {
   118     cacheFile->AppendNative(nsDependentCString(aFileName));
   119   }
   121   return cacheFile.forget();
   122 }
   125 //-------------------------------------------------------------------------
   126 nsresult
   127 DataStruct::WriteCache(nsISupports* aData, uint32_t aDataLen)
   128 {
   129   // Get a new path and file to the temp directory
   130   nsCOMPtr<nsIFile> cacheFile = GetFileSpec(mCacheFileName);
   131   if (cacheFile) {
   132     // remember the file name
   133     if (!mCacheFileName) {
   134       nsXPIDLCString fName;
   135       cacheFile->GetNativeLeafName(fName);
   136       mCacheFileName = strdup(fName);
   137     }
   139     // write out the contents of the clipboard
   140     // to the file
   141     //uint32_t bytes;
   142     nsCOMPtr<nsIOutputStream> outStr;
   144     NS_NewLocalFileOutputStream(getter_AddRefs(outStr),
   145                                 cacheFile);
   147     if (!outStr) return NS_ERROR_FAILURE;
   149     void* buff = nullptr;
   150     nsPrimitiveHelpers::CreateDataFromPrimitive ( mFlavor.get(), aData, &buff, aDataLen );
   151     if ( buff ) {
   152       uint32_t ignored;
   153       outStr->Write(reinterpret_cast<char*>(buff), aDataLen, &ignored);
   154       nsMemory::Free(buff);
   155       return NS_OK;
   156     }
   157   }
   158   return NS_ERROR_FAILURE;
   159 }
   162 //-------------------------------------------------------------------------
   163 nsresult
   164 DataStruct::ReadCache(nsISupports** aData, uint32_t* aDataLen)
   165 {
   166   // if we don't have a cache filename we are out of luck
   167   if (!mCacheFileName)
   168     return NS_ERROR_FAILURE;
   170   // get the path and file name
   171   nsCOMPtr<nsIFile> cacheFile = GetFileSpec(mCacheFileName);
   172   bool exists;
   173   if ( cacheFile && NS_SUCCEEDED(cacheFile->Exists(&exists)) && exists ) {
   174     // get the size of the file
   175     int64_t fileSize;
   176     int64_t max32 = 0xFFFFFFFF;
   177     cacheFile->GetFileSize(&fileSize);
   178     if (fileSize > max32)
   179       return NS_ERROR_OUT_OF_MEMORY;
   181     uint32_t size = uint32_t(fileSize);
   182     // create new memory for the large clipboard data
   183     nsAutoArrayPtr<char> data(new char[size]);
   184     if ( !data )
   185       return NS_ERROR_OUT_OF_MEMORY;
   187     // now read it all in
   188     nsCOMPtr<nsIInputStream> inStr;
   189     NS_NewLocalFileInputStream( getter_AddRefs(inStr),
   190                                 cacheFile);
   192     if (!cacheFile) return NS_ERROR_FAILURE;
   194     nsresult rv = inStr->Read(data, fileSize, aDataLen);
   196     // make sure we got all the data ok
   197     if (NS_SUCCEEDED(rv) && *aDataLen == size) {
   198       nsPrimitiveHelpers::CreatePrimitiveForData ( mFlavor.get(), data, fileSize, aData );
   199       return *aData ? NS_OK : NS_ERROR_FAILURE;
   200     }
   202     // zero the return params
   203     *aData    = nullptr;
   204     *aDataLen = 0;
   205   }
   207   return NS_ERROR_FAILURE;
   208 }
   211 //-------------------------------------------------------------------------
   212 //
   213 // Transferable constructor
   214 //
   215 //-------------------------------------------------------------------------
   216 nsTransferable::nsTransferable()
   217   : mPrivateData(false)
   218 #ifdef DEBUG
   219   , mInitialized(false)
   220 #endif
   221 {
   222 }
   224 //-------------------------------------------------------------------------
   225 //
   226 // Transferable destructor
   227 //
   228 //-------------------------------------------------------------------------
   229 nsTransferable::~nsTransferable()
   230 {
   231 }
   234 NS_IMETHODIMP
   235 nsTransferable::Init(nsILoadContext* aContext)
   236 {
   237   MOZ_ASSERT(!mInitialized);
   239   if (aContext) {
   240     mPrivateData = aContext->UsePrivateBrowsing();
   241   }
   242 #ifdef DEBUG
   243   mInitialized = true;
   244 #endif
   245   return NS_OK;
   246 }
   248 //
   249 // GetTransferDataFlavors
   250 //
   251 // Returns a copy of the internal list of flavors. This does NOT take into 
   252 // account any converter that may be registered. This list consists of
   253 // nsISupportsCString objects so that the flavor list can be accessed from JS.
   254 //
   255 nsresult
   256 nsTransferable::GetTransferDataFlavors(nsISupportsArray ** aDataFlavorList)
   257 {
   258   MOZ_ASSERT(mInitialized);
   260   nsresult rv = NS_NewISupportsArray ( aDataFlavorList );
   261   if (NS_FAILED(rv)) return rv;
   263   for ( uint32_t i=0; i<mDataArray.Length(); ++i ) {
   264     DataStruct& data = mDataArray.ElementAt(i);
   265     nsCOMPtr<nsISupportsCString> flavorWrapper = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
   266     if ( flavorWrapper ) {
   267       flavorWrapper->SetData ( data.GetFlavor() );
   268       nsCOMPtr<nsISupports> genericWrapper ( do_QueryInterface(flavorWrapper) );
   269       (*aDataFlavorList)->AppendElement( genericWrapper );
   270     }
   271   }
   273   return NS_OK;
   274 }
   277 //
   278 // GetTransferData
   279 //
   280 // Returns the data of the requested flavor, obtained from either having the data on hand or
   281 // using a converter to get it. The data is wrapped in a nsISupports primitive so that it is
   282 // accessible from JS.
   283 //
   284 NS_IMETHODIMP
   285 nsTransferable::GetTransferData(const char *aFlavor, nsISupports **aData, uint32_t *aDataLen)
   286 {
   287   MOZ_ASSERT(mInitialized);
   289   NS_ENSURE_ARG_POINTER(aFlavor && aData && aDataLen);
   291   nsresult rv = NS_OK;
   292   nsCOMPtr<nsISupports> savedData;
   294   // first look and see if the data is present in one of the intrinsic flavors
   295   uint32_t i;
   296   for (i = 0; i < mDataArray.Length(); ++i ) {
   297     DataStruct& data = mDataArray.ElementAt(i);
   298     if ( data.GetFlavor().Equals(aFlavor) ) {
   299       nsCOMPtr<nsISupports> dataBytes;
   300       uint32_t len;
   301       data.GetData(getter_AddRefs(dataBytes), &len);
   302       if (len == kFlavorHasDataProvider && dataBytes) {
   303         // do we have a data provider?
   304         nsCOMPtr<nsIFlavorDataProvider> dataProvider = do_QueryInterface(dataBytes);
   305         if (dataProvider) {
   306           rv = dataProvider->GetFlavorData(this, aFlavor,
   307                                            getter_AddRefs(dataBytes), &len);
   308           if (NS_FAILED(rv))
   309             break;    // the provider failed. fall into the converter code below.
   310         }
   311       }
   312       if (dataBytes && len > 0) { // XXXmats why is zero length not ok?
   313         *aDataLen = len;
   314         dataBytes.forget(aData);
   315         return NS_OK;
   316       }
   317       savedData = dataBytes;  // return this if format converter fails
   318       break;
   319     }
   320   }
   322   bool found = false;
   324   // if not, try using a format converter to get the requested flavor
   325   if ( mFormatConv ) {
   326     for (i = 0; i < mDataArray.Length(); ++i) {
   327       DataStruct& data = mDataArray.ElementAt(i);
   328       bool canConvert = false;
   329       mFormatConv->CanConvert(data.GetFlavor().get(), aFlavor, &canConvert);
   330       if ( canConvert ) {
   331         nsCOMPtr<nsISupports> dataBytes;
   332         uint32_t len;
   333         data.GetData(getter_AddRefs(dataBytes), &len);
   334         if (len == kFlavorHasDataProvider && dataBytes) {
   335           // do we have a data provider?
   336           nsCOMPtr<nsIFlavorDataProvider> dataProvider = do_QueryInterface(dataBytes);
   337           if (dataProvider) {
   338             rv = dataProvider->GetFlavorData(this, aFlavor,
   339                                              getter_AddRefs(dataBytes), &len);
   340             if (NS_FAILED(rv))
   341               break;  // give up
   342           }
   343         }
   344         mFormatConv->Convert(data.GetFlavor().get(), dataBytes, len, aFlavor, aData, aDataLen);
   345         found = true;
   346         break;
   347       }
   348     }
   349   }
   351   // for backward compatibility
   352   if (!found) {
   353     savedData.forget(aData);
   354     *aDataLen = 0;
   355   }
   357   return found ? NS_OK : NS_ERROR_FAILURE;
   358 }
   361 //
   362 // GetAnyTransferData
   363 //
   364 // Returns the data of the first flavor found. Caller is responsible for deleting the
   365 // flavor string.
   366 // 
   367 NS_IMETHODIMP
   368 nsTransferable::GetAnyTransferData(char **aFlavor, nsISupports **aData, uint32_t *aDataLen)
   369 {
   370   MOZ_ASSERT(mInitialized);
   372   NS_ENSURE_ARG_POINTER(aFlavor && aData && aDataLen);
   374   for ( uint32_t i=0; i < mDataArray.Length(); ++i ) {
   375     DataStruct& data = mDataArray.ElementAt(i);
   376     if (data.IsDataAvailable()) {
   377       *aFlavor = ToNewCString(data.GetFlavor());
   378       data.GetData(aData, aDataLen);
   379       return NS_OK;
   380     }
   381   }
   383   return NS_ERROR_FAILURE;
   384 }
   387 //
   388 // SetTransferData
   389 //
   390 //
   391 // 
   392 NS_IMETHODIMP
   393 nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, uint32_t aDataLen)
   394 {
   395   MOZ_ASSERT(mInitialized);
   397   NS_ENSURE_ARG(aFlavor);
   399   // first check our intrinsic flavors to see if one has been registered.
   400   uint32_t i = 0;
   401   for (i = 0; i < mDataArray.Length(); ++i) {
   402     DataStruct& data = mDataArray.ElementAt(i);
   403     if ( data.GetFlavor().Equals(aFlavor) ) {
   404       data.SetData ( aData, aDataLen );
   405       return NS_OK;
   406     }
   407   }
   409   // if not, try using a format converter to find a flavor to put the data in
   410   if ( mFormatConv ) {
   411     for (i = 0; i < mDataArray.Length(); ++i) {
   412       DataStruct& data = mDataArray.ElementAt(i);
   413       bool canConvert = false;
   414       mFormatConv->CanConvert(aFlavor, data.GetFlavor().get(), &canConvert);
   416       if ( canConvert ) {
   417         nsCOMPtr<nsISupports> ConvertedData;
   418         uint32_t ConvertedLen;
   419         mFormatConv->Convert(aFlavor, aData, aDataLen, data.GetFlavor().get(), getter_AddRefs(ConvertedData), &ConvertedLen);
   420         data.SetData(ConvertedData, ConvertedLen);
   421         return NS_OK;
   422       }
   423     }
   424   }
   426   // Can't set data neither directly nor through converter. Just add this flavor and try again
   427   nsresult result = NS_ERROR_FAILURE;
   428   if ( NS_SUCCEEDED(AddDataFlavor(aFlavor)) )
   429     result = SetTransferData (aFlavor, aData, aDataLen);
   431   return result;
   432 }
   435 //
   436 // AddDataFlavor
   437 //
   438 // Adds a data flavor to our list with no data. Error if it already exists.
   439 // 
   440 NS_IMETHODIMP
   441 nsTransferable::AddDataFlavor(const char *aDataFlavor)
   442 {
   443   MOZ_ASSERT(mInitialized);
   445   if (GetDataForFlavor (mDataArray, aDataFlavor) != mDataArray.NoIndex)
   446     return NS_ERROR_FAILURE;
   448   // Create a new "slot" for the data
   449   mDataArray.AppendElement(DataStruct ( aDataFlavor ));
   451   return NS_OK;
   452 }
   455 //
   456 // RemoveDataFlavor
   457 //
   458 // Removes a data flavor (and causes the data to be destroyed). Error if
   459 // the requested flavor is not present.
   460 //
   461 NS_IMETHODIMP
   462 nsTransferable::RemoveDataFlavor(const char *aDataFlavor)
   463 {
   464   MOZ_ASSERT(mInitialized);
   466   uint32_t idx;
   467   if ((idx = GetDataForFlavor(mDataArray, aDataFlavor)) != mDataArray.NoIndex) {
   468     mDataArray.RemoveElementAt (idx);
   469     return NS_OK;
   470   }
   471   return NS_ERROR_FAILURE;
   472 }
   475 /**
   476   * 
   477   *
   478   */
   479 NS_IMETHODIMP
   480 nsTransferable::IsLargeDataSet(bool *_retval)
   481 {
   482   MOZ_ASSERT(mInitialized);
   484   NS_ENSURE_ARG_POINTER(_retval);
   485   *_retval = false;
   486   return NS_OK;
   487 }
   490 /**
   491   * 
   492   *
   493   */
   494 NS_IMETHODIMP nsTransferable::SetConverter(nsIFormatConverter * aConverter)
   495 {
   496   MOZ_ASSERT(mInitialized);
   498   mFormatConv = aConverter;
   499   return NS_OK;
   500 }
   503 /**
   504   * 
   505   *
   506   */
   507 NS_IMETHODIMP nsTransferable::GetConverter(nsIFormatConverter * *aConverter)
   508 {
   509   MOZ_ASSERT(mInitialized);
   511   NS_ENSURE_ARG_POINTER(aConverter);
   512   *aConverter = mFormatConv;
   513   NS_IF_ADDREF(*aConverter);
   514   return NS_OK;
   515 }
   518 //
   519 // FlavorsTransferableCanImport
   520 //
   521 // Computes a list of flavors that the transferable can accept into it, either through
   522 // intrinsic knowledge or input data converters.
   523 //
   524 NS_IMETHODIMP
   525 nsTransferable::FlavorsTransferableCanImport(nsISupportsArray **_retval)
   526 {
   527   MOZ_ASSERT(mInitialized);
   529   NS_ENSURE_ARG_POINTER(_retval);
   531   // Get the flavor list, and on to the end of it, append the list of flavors we
   532   // can also get to through a converter. This is so that we can just walk the list
   533   // in one go, looking for the desired flavor.
   534   GetTransferDataFlavors(_retval);                        // addrefs
   535   nsCOMPtr<nsIFormatConverter> converter;
   536   GetConverter(getter_AddRefs(converter));
   537   if ( converter ) {
   538     nsCOMPtr<nsISupportsArray> convertedList;
   539     converter->GetInputDataFlavors(getter_AddRefs(convertedList));
   541     if ( convertedList ) {
   542       uint32_t importListLen;
   543       convertedList->Count(&importListLen);
   545       for ( uint32_t i=0; i < importListLen; ++i ) {
   546         nsCOMPtr<nsISupports> genericFlavor;
   547         convertedList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
   549         nsCOMPtr<nsISupportsCString> flavorWrapper ( do_QueryInterface (genericFlavor) );
   550         nsAutoCString flavorStr;
   551         flavorWrapper->GetData( flavorStr );
   553         if (GetDataForFlavor (mDataArray, flavorStr.get())
   554             == mDataArray.NoIndex) // Don't append if already in intrinsic list
   555           (*_retval)->AppendElement (genericFlavor);
   556       } // foreach flavor that can be converted to
   557     }
   558   } // if a converter exists
   560   return NS_OK;  
   561 } // FlavorsTransferableCanImport
   564 //
   565 // FlavorsTransferableCanExport
   566 //
   567 // Computes a list of flavors that the transferable can export, either through
   568 // intrinsic knowledge or output data converters.
   569 //
   570 NS_IMETHODIMP
   571 nsTransferable::FlavorsTransferableCanExport(nsISupportsArray **_retval)
   572 {
   573   MOZ_ASSERT(mInitialized);
   575   NS_ENSURE_ARG_POINTER(_retval);
   577   // Get the flavor list, and on to the end of it, append the list of flavors we
   578   // can also get to through a converter. This is so that we can just walk the list
   579   // in one go, looking for the desired flavor.
   580   GetTransferDataFlavors(_retval);  // addrefs
   581   nsCOMPtr<nsIFormatConverter> converter;
   582   GetConverter(getter_AddRefs(converter));
   583   if ( converter ) {
   584     nsCOMPtr<nsISupportsArray> convertedList;
   585     converter->GetOutputDataFlavors(getter_AddRefs(convertedList));
   587     if ( convertedList ) {
   588       uint32_t importListLen;
   589       convertedList->Count(&importListLen);
   591       for ( uint32_t i=0; i < importListLen; ++i ) {
   592         nsCOMPtr<nsISupports> genericFlavor;
   593         convertedList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
   595         nsCOMPtr<nsISupportsCString> flavorWrapper ( do_QueryInterface (genericFlavor) );
   596         nsAutoCString flavorStr;
   597         flavorWrapper->GetData( flavorStr );
   599         if (GetDataForFlavor (mDataArray, flavorStr.get())
   600             == mDataArray.NoIndex) // Don't append if already in intrinsic list
   601           (*_retval)->AppendElement (genericFlavor);
   602       } // foreach flavor that can be converted to
   603     }
   604   } // if a converter exists
   606   return NS_OK;
   607 } // FlavorsTransferableCanExport
   609 NS_IMETHODIMP
   610 nsTransferable::GetIsPrivateData(bool *aIsPrivateData)
   611 {
   612   MOZ_ASSERT(mInitialized);
   614   NS_ENSURE_ARG_POINTER(aIsPrivateData);
   616   *aIsPrivateData = mPrivateData;
   618   return NS_OK;
   619 }
   621 NS_IMETHODIMP
   622 nsTransferable::SetIsPrivateData(bool aIsPrivateData)
   623 {
   624   MOZ_ASSERT(mInitialized);
   626   mPrivateData = aIsPrivateData;
   628   return NS_OK;
   629 }

mercurial