1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsDataObj.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2140 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/ArrayUtils.h" 1.10 + 1.11 +#include <ole2.h> 1.12 +#include <shlobj.h> 1.13 + 1.14 +#include "nsDataObj.h" 1.15 +#include "nsClipboard.h" 1.16 +#include "nsReadableUtils.h" 1.17 +#include "nsITransferable.h" 1.18 +#include "nsISupportsPrimitives.h" 1.19 +#include "IEnumFE.h" 1.20 +#include "nsPrimitiveHelpers.h" 1.21 +#include "nsXPIDLString.h" 1.22 +#include "nsImageClipboard.h" 1.23 +#include "nsCRT.h" 1.24 +#include "nsPrintfCString.h" 1.25 +#include "nsIStringBundle.h" 1.26 +#include "nsEscape.h" 1.27 +#include "nsIURL.h" 1.28 +#include "nsNetUtil.h" 1.29 +#include "nsXPCOMStrings.h" 1.30 +#include "nscore.h" 1.31 +#include "nsDirectoryServiceDefs.h" 1.32 +#include "nsITimer.h" 1.33 +#include "nsThreadUtils.h" 1.34 +#include "mozilla/Preferences.h" 1.35 + 1.36 +#include "WinUtils.h" 1.37 +#include "mozilla/LazyIdleThread.h" 1.38 +#include "mozilla/WindowsVersion.h" 1.39 +#include <algorithm> 1.40 + 1.41 + 1.42 +using namespace mozilla; 1.43 +using namespace mozilla::widget; 1.44 + 1.45 +#define DEFAULT_THREAD_TIMEOUT_MS 30000 1.46 + 1.47 +NS_IMPL_ISUPPORTS(nsDataObj::CStream, nsIStreamListener) 1.48 + 1.49 +//----------------------------------------------------------------------------- 1.50 +// CStream implementation 1.51 +nsDataObj::CStream::CStream() : 1.52 + mChannelRead(false), 1.53 + mStreamRead(0) 1.54 +{ 1.55 +} 1.56 + 1.57 +//----------------------------------------------------------------------------- 1.58 +nsDataObj::CStream::~CStream() 1.59 +{ 1.60 +} 1.61 + 1.62 +//----------------------------------------------------------------------------- 1.63 +// helper - initializes the stream 1.64 +nsresult nsDataObj::CStream::Init(nsIURI *pSourceURI) 1.65 +{ 1.66 + nsresult rv; 1.67 + rv = NS_NewChannel(getter_AddRefs(mChannel), pSourceURI, 1.68 + nullptr, nullptr, nullptr, 1.69 + nsIRequest::LOAD_FROM_CACHE); 1.70 + NS_ENSURE_SUCCESS(rv, rv); 1.71 + rv = mChannel->AsyncOpen(this, nullptr); 1.72 + NS_ENSURE_SUCCESS(rv, rv); 1.73 + return NS_OK; 1.74 +} 1.75 + 1.76 +//----------------------------------------------------------------------------- 1.77 +// IUnknown's QueryInterface, nsISupport's AddRef and Release are shared by 1.78 +// IUnknown and nsIStreamListener. 1.79 +STDMETHODIMP nsDataObj::CStream::QueryInterface(REFIID refiid, void** ppvResult) 1.80 +{ 1.81 + *ppvResult = nullptr; 1.82 + if (IID_IUnknown == refiid || 1.83 + refiid == IID_IStream) 1.84 + 1.85 + { 1.86 + *ppvResult = this; 1.87 + } 1.88 + 1.89 + if (nullptr != *ppvResult) 1.90 + { 1.91 + ((LPUNKNOWN)*ppvResult)->AddRef(); 1.92 + return S_OK; 1.93 + } 1.94 + 1.95 + return E_NOINTERFACE; 1.96 +} 1.97 + 1.98 +// nsIStreamListener implementation 1.99 +NS_IMETHODIMP 1.100 +nsDataObj::CStream::OnDataAvailable(nsIRequest *aRequest, 1.101 + nsISupports *aContext, 1.102 + nsIInputStream *aInputStream, 1.103 + uint64_t aOffset, // offset within the stream 1.104 + uint32_t aCount) // bytes available on this call 1.105 +{ 1.106 + // Extend the write buffer for the incoming data. 1.107 + uint8_t* buffer = mChannelData.AppendElements(aCount); 1.108 + if (buffer == nullptr) 1.109 + return NS_ERROR_OUT_OF_MEMORY; 1.110 + NS_ASSERTION((mChannelData.Length() == (aOffset + aCount)), 1.111 + "stream length mismatch w/write buffer"); 1.112 + 1.113 + // Read() may not return aCount on a single call, so loop until we've 1.114 + // accumulated all the data OnDataAvailable has promised. 1.115 + nsresult rv; 1.116 + uint32_t odaBytesReadTotal = 0; 1.117 + do { 1.118 + uint32_t bytesReadByCall = 0; 1.119 + rv = aInputStream->Read((char*)(buffer + odaBytesReadTotal), 1.120 + aCount, &bytesReadByCall); 1.121 + odaBytesReadTotal += bytesReadByCall; 1.122 + } while (aCount < odaBytesReadTotal && NS_SUCCEEDED(rv)); 1.123 + return rv; 1.124 +} 1.125 + 1.126 +NS_IMETHODIMP nsDataObj::CStream::OnStartRequest(nsIRequest *aRequest, 1.127 + nsISupports *aContext) 1.128 +{ 1.129 + mChannelResult = NS_OK; 1.130 + return NS_OK; 1.131 +} 1.132 + 1.133 +NS_IMETHODIMP nsDataObj::CStream::OnStopRequest(nsIRequest *aRequest, 1.134 + nsISupports *aContext, 1.135 + nsresult aStatusCode) 1.136 +{ 1.137 + mChannelRead = true; 1.138 + mChannelResult = aStatusCode; 1.139 + return NS_OK; 1.140 +} 1.141 + 1.142 +// Pumps thread messages while waiting for the async listener operation to 1.143 +// complete. Failing this call will fail the stream incall from Windows 1.144 +// and cancel the operation. 1.145 +nsresult nsDataObj::CStream::WaitForCompletion() 1.146 +{ 1.147 + // We are guaranteed OnStopRequest will get called, so this should be ok. 1.148 + while (!mChannelRead) { 1.149 + // Pump messages 1.150 + NS_ProcessNextEvent(nullptr, true); 1.151 + } 1.152 + 1.153 + if (!mChannelData.Length()) 1.154 + mChannelResult = NS_ERROR_FAILURE; 1.155 + 1.156 + return mChannelResult; 1.157 +} 1.158 + 1.159 +//----------------------------------------------------------------------------- 1.160 +// IStream 1.161 +STDMETHODIMP nsDataObj::CStream::Clone(IStream** ppStream) 1.162 +{ 1.163 + return E_NOTIMPL; 1.164 +} 1.165 + 1.166 +//----------------------------------------------------------------------------- 1.167 +STDMETHODIMP nsDataObj::CStream::Commit(DWORD dwFrags) 1.168 +{ 1.169 + return E_NOTIMPL; 1.170 +} 1.171 + 1.172 +//----------------------------------------------------------------------------- 1.173 +STDMETHODIMP nsDataObj::CStream::CopyTo(IStream* pDestStream, 1.174 + ULARGE_INTEGER nBytesToCopy, 1.175 + ULARGE_INTEGER* nBytesRead, 1.176 + ULARGE_INTEGER* nBytesWritten) 1.177 +{ 1.178 + return E_NOTIMPL; 1.179 +} 1.180 + 1.181 +//----------------------------------------------------------------------------- 1.182 +STDMETHODIMP nsDataObj::CStream::LockRegion(ULARGE_INTEGER nStart, 1.183 + ULARGE_INTEGER nBytes, 1.184 + DWORD dwFlags) 1.185 +{ 1.186 + return E_NOTIMPL; 1.187 +} 1.188 + 1.189 +//----------------------------------------------------------------------------- 1.190 +STDMETHODIMP nsDataObj::CStream::Read(void* pvBuffer, 1.191 + ULONG nBytesToRead, 1.192 + ULONG* nBytesRead) 1.193 +{ 1.194 + // Wait for the write into our buffer to complete via the stream listener. 1.195 + // We can't respond to this by saying "call us back later". 1.196 + if (NS_FAILED(WaitForCompletion())) 1.197 + return E_FAIL; 1.198 + 1.199 + // Bytes left for Windows to read out of our buffer 1.200 + ULONG bytesLeft = mChannelData.Length() - mStreamRead; 1.201 + // Let Windows know what we will hand back, usually this is the entire buffer 1.202 + *nBytesRead = std::min(bytesLeft, nBytesToRead); 1.203 + // Copy the buffer data over 1.204 + memcpy(pvBuffer, ((char*)mChannelData.Elements() + mStreamRead), *nBytesRead); 1.205 + // Update our bytes read tracking 1.206 + mStreamRead += *nBytesRead; 1.207 + return S_OK; 1.208 +} 1.209 + 1.210 +//----------------------------------------------------------------------------- 1.211 +STDMETHODIMP nsDataObj::CStream::Revert(void) 1.212 +{ 1.213 + return E_NOTIMPL; 1.214 +} 1.215 + 1.216 +//----------------------------------------------------------------------------- 1.217 +STDMETHODIMP nsDataObj::CStream::Seek(LARGE_INTEGER nMove, 1.218 + DWORD dwOrigin, 1.219 + ULARGE_INTEGER* nNewPos) 1.220 +{ 1.221 + if (nNewPos == nullptr) 1.222 + return STG_E_INVALIDPOINTER; 1.223 + 1.224 + if (nMove.LowPart == 0 && nMove.HighPart == 0 && 1.225 + (dwOrigin == STREAM_SEEK_SET || dwOrigin == STREAM_SEEK_CUR)) { 1.226 + nNewPos->LowPart = 0; 1.227 + nNewPos->HighPart = 0; 1.228 + return S_OK; 1.229 + } 1.230 + 1.231 + return E_NOTIMPL; 1.232 +} 1.233 + 1.234 +//----------------------------------------------------------------------------- 1.235 +STDMETHODIMP nsDataObj::CStream::SetSize(ULARGE_INTEGER nNewSize) 1.236 +{ 1.237 + return E_NOTIMPL; 1.238 +} 1.239 + 1.240 +//----------------------------------------------------------------------------- 1.241 +STDMETHODIMP nsDataObj::CStream::Stat(STATSTG* statstg, DWORD dwFlags) 1.242 +{ 1.243 + if (statstg == nullptr) 1.244 + return STG_E_INVALIDPOINTER; 1.245 + 1.246 + if (!mChannel || NS_FAILED(WaitForCompletion())) 1.247 + return E_FAIL; 1.248 + 1.249 + memset((void*)statstg, 0, sizeof(STATSTG)); 1.250 + 1.251 + if (dwFlags != STATFLAG_NONAME) 1.252 + { 1.253 + nsCOMPtr<nsIURI> sourceURI; 1.254 + if (NS_FAILED(mChannel->GetURI(getter_AddRefs(sourceURI)))) { 1.255 + return E_FAIL; 1.256 + } 1.257 + 1.258 + nsAutoCString strFileName; 1.259 + nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(sourceURI); 1.260 + sourceURL->GetFileName(strFileName); 1.261 + 1.262 + if (strFileName.IsEmpty()) 1.263 + return E_FAIL; 1.264 + 1.265 + NS_UnescapeURL(strFileName); 1.266 + NS_ConvertUTF8toUTF16 wideFileName(strFileName); 1.267 + 1.268 + uint32_t nMaxNameLength = (wideFileName.Length()*2) + 2; 1.269 + void * retBuf = CoTaskMemAlloc(nMaxNameLength); // freed by caller 1.270 + if (!retBuf) 1.271 + return STG_E_INSUFFICIENTMEMORY; 1.272 + 1.273 + ZeroMemory(retBuf, nMaxNameLength); 1.274 + memcpy(retBuf, wideFileName.get(), wideFileName.Length()*2); 1.275 + statstg->pwcsName = (LPOLESTR)retBuf; 1.276 + } 1.277 + 1.278 + SYSTEMTIME st; 1.279 + 1.280 + statstg->type = STGTY_STREAM; 1.281 + 1.282 + GetSystemTime(&st); 1.283 + SystemTimeToFileTime((const SYSTEMTIME*)&st, (LPFILETIME)&statstg->mtime); 1.284 + statstg->ctime = statstg->atime = statstg->mtime; 1.285 + 1.286 + statstg->cbSize.LowPart = (DWORD)mChannelData.Length(); 1.287 + statstg->grfMode = STGM_READ; 1.288 + statstg->grfLocksSupported = LOCK_ONLYONCE; 1.289 + statstg->clsid = CLSID_NULL; 1.290 + 1.291 + return S_OK; 1.292 +} 1.293 + 1.294 +//----------------------------------------------------------------------------- 1.295 +STDMETHODIMP nsDataObj::CStream::UnlockRegion(ULARGE_INTEGER nStart, 1.296 + ULARGE_INTEGER nBytes, 1.297 + DWORD dwFlags) 1.298 +{ 1.299 + return E_NOTIMPL; 1.300 +} 1.301 + 1.302 +//----------------------------------------------------------------------------- 1.303 +STDMETHODIMP nsDataObj::CStream::Write(const void* pvBuffer, 1.304 + ULONG nBytesToRead, 1.305 + ULONG* nBytesRead) 1.306 +{ 1.307 + return E_NOTIMPL; 1.308 +} 1.309 + 1.310 +//----------------------------------------------------------------------------- 1.311 +HRESULT nsDataObj::CreateStream(IStream **outStream) 1.312 +{ 1.313 + NS_ENSURE_TRUE(outStream, E_INVALIDARG); 1.314 + 1.315 + nsresult rv = NS_ERROR_FAILURE; 1.316 + nsAutoString wideFileName; 1.317 + nsCOMPtr<nsIURI> sourceURI; 1.318 + HRESULT res; 1.319 + 1.320 + res = GetDownloadDetails(getter_AddRefs(sourceURI), 1.321 + wideFileName); 1.322 + if(FAILED(res)) 1.323 + return res; 1.324 + 1.325 + nsDataObj::CStream *pStream = new nsDataObj::CStream(); 1.326 + NS_ENSURE_TRUE(pStream, E_OUTOFMEMORY); 1.327 + 1.328 + pStream->AddRef(); 1.329 + 1.330 + rv = pStream->Init(sourceURI); 1.331 + if (NS_FAILED(rv)) 1.332 + { 1.333 + pStream->Release(); 1.334 + return E_FAIL; 1.335 + } 1.336 + *outStream = pStream; 1.337 + 1.338 + return S_OK; 1.339 +} 1.340 + 1.341 +static GUID CLSID_nsDataObj = 1.342 + { 0x1bba7640, 0xdf52, 0x11cf, { 0x82, 0x7b, 0, 0xa0, 0x24, 0x3a, 0xe5, 0x05 } }; 1.343 + 1.344 +/* 1.345 + * deliberately not using MAX_PATH. This is because on platforms < XP 1.346 + * a file created with a long filename may be mishandled by the shell 1.347 + * resulting in it not being able to be deleted or moved. 1.348 + * See bug 250392 for more details. 1.349 + */ 1.350 +#define NS_MAX_FILEDESCRIPTOR 128 + 1 1.351 + 1.352 +/* 1.353 + * Class nsDataObj 1.354 + */ 1.355 + 1.356 +//----------------------------------------------------- 1.357 +// construction 1.358 +//----------------------------------------------------- 1.359 +nsDataObj::nsDataObj(nsIURI * uri) 1.360 + : m_cRef(0), mTransferable(nullptr), 1.361 + mIsAsyncMode(FALSE), mIsInOperation(FALSE) 1.362 +{ 1.363 + mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS, 1.364 + NS_LITERAL_CSTRING("nsDataObj"), 1.365 + LazyIdleThread::ManualShutdown); 1.366 + m_enumFE = new CEnumFormatEtc(); 1.367 + m_enumFE->AddRef(); 1.368 + 1.369 + if (uri) { 1.370 + // A URI was obtained, so pass this through to the DataObject 1.371 + // so it can create a SourceURL for CF_HTML flavour 1.372 + uri->GetSpec(mSourceURL); 1.373 + } 1.374 +} 1.375 +//----------------------------------------------------- 1.376 +// destruction 1.377 +//----------------------------------------------------- 1.378 +nsDataObj::~nsDataObj() 1.379 +{ 1.380 + NS_IF_RELEASE(mTransferable); 1.381 + 1.382 + mDataFlavors.Clear(); 1.383 + 1.384 + m_enumFE->Release(); 1.385 + 1.386 + // Free arbitrary system formats 1.387 + for (uint32_t idx = 0; idx < mDataEntryList.Length(); idx++) { 1.388 + CoTaskMemFree(mDataEntryList[idx]->fe.ptd); 1.389 + ReleaseStgMedium(&mDataEntryList[idx]->stgm); 1.390 + CoTaskMemFree(mDataEntryList[idx]); 1.391 + } 1.392 +} 1.393 + 1.394 + 1.395 +//----------------------------------------------------- 1.396 +// IUnknown interface methods - see inknown.h for documentation 1.397 +//----------------------------------------------------- 1.398 +STDMETHODIMP nsDataObj::QueryInterface(REFIID riid, void** ppv) 1.399 +{ 1.400 + *ppv=nullptr; 1.401 + 1.402 + if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) { 1.403 + *ppv = this; 1.404 + AddRef(); 1.405 + return S_OK; 1.406 + } else if (IID_IAsyncOperation == riid) { 1.407 + *ppv = static_cast<IAsyncOperation*>(this); 1.408 + AddRef(); 1.409 + return S_OK; 1.410 + } 1.411 + 1.412 + return E_NOINTERFACE; 1.413 +} 1.414 + 1.415 +//----------------------------------------------------- 1.416 +STDMETHODIMP_(ULONG) nsDataObj::AddRef() 1.417 +{ 1.418 + ++m_cRef; 1.419 + NS_LOG_ADDREF(this, m_cRef, "nsDataObj", sizeof(*this)); 1.420 + return m_cRef; 1.421 +} 1.422 + 1.423 + 1.424 +//----------------------------------------------------- 1.425 +STDMETHODIMP_(ULONG) nsDataObj::Release() 1.426 +{ 1.427 + --m_cRef; 1.428 + 1.429 + NS_LOG_RELEASE(this, m_cRef, "nsDataObj"); 1.430 + if (0 != m_cRef) 1.431 + return m_cRef; 1.432 + 1.433 + // We have released our last ref on this object and need to delete the 1.434 + // temp file. External app acting as drop target may still need to open the 1.435 + // temp file. Addref a timer so it can delay deleting file and destroying 1.436 + // this object. Delete file anyway and destroy this obj if there's a problem. 1.437 + if (mCachedTempFile) { 1.438 + nsresult rv; 1.439 + mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); 1.440 + if (NS_SUCCEEDED(rv)) { 1.441 + mTimer->InitWithFuncCallback(nsDataObj::RemoveTempFile, this, 1.442 + 500, nsITimer::TYPE_ONE_SHOT); 1.443 + return AddRef(); 1.444 + } 1.445 + mCachedTempFile->Remove(false); 1.446 + mCachedTempFile = nullptr; 1.447 + } 1.448 + 1.449 + delete this; 1.450 + 1.451 + return 0; 1.452 +} 1.453 + 1.454 +//----------------------------------------------------- 1.455 +BOOL nsDataObj::FormatsMatch(const FORMATETC& source, const FORMATETC& target) const 1.456 +{ 1.457 + if ((source.cfFormat == target.cfFormat) && 1.458 + (source.dwAspect & target.dwAspect) && 1.459 + (source.tymed & target.tymed)) { 1.460 + return TRUE; 1.461 + } else { 1.462 + return FALSE; 1.463 + } 1.464 +} 1.465 + 1.466 +//----------------------------------------------------- 1.467 +// IDataObject methods 1.468 +//----------------------------------------------------- 1.469 +STDMETHODIMP nsDataObj::GetData(LPFORMATETC aFormat, LPSTGMEDIUM pSTM) 1.470 +{ 1.471 + if (!mTransferable) 1.472 + return DV_E_FORMATETC; 1.473 + 1.474 + uint32_t dfInx = 0; 1.475 + 1.476 + static CLIPFORMAT fileDescriptorFlavorA = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORA ); 1.477 + static CLIPFORMAT fileDescriptorFlavorW = ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORW ); 1.478 + static CLIPFORMAT uniformResourceLocatorA = ::RegisterClipboardFormat( CFSTR_INETURLA ); 1.479 + static CLIPFORMAT uniformResourceLocatorW = ::RegisterClipboardFormat( CFSTR_INETURLW ); 1.480 + static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat( CFSTR_FILECONTENTS ); 1.481 + static CLIPFORMAT PreferredDropEffect = ::RegisterClipboardFormat( CFSTR_PREFERREDDROPEFFECT ); 1.482 + 1.483 + // Arbitrary system formats are used for image feedback during drag 1.484 + // and drop. We are responsible for storing these internally during 1.485 + // drag operations. 1.486 + LPDATAENTRY pde; 1.487 + if (LookupArbitraryFormat(aFormat, &pde, FALSE)) { 1.488 + return CopyMediumData(pSTM, &pde->stgm, aFormat, FALSE) 1.489 + ? S_OK : E_UNEXPECTED; 1.490 + } 1.491 + 1.492 + // Firefox internal formats 1.493 + ULONG count; 1.494 + FORMATETC fe; 1.495 + m_enumFE->Reset(); 1.496 + while (NOERROR == m_enumFE->Next(1, &fe, &count) 1.497 + && dfInx < mDataFlavors.Length()) { 1.498 + nsCString& df = mDataFlavors.ElementAt(dfInx); 1.499 + if (FormatsMatch(fe, *aFormat)) { 1.500 + pSTM->pUnkForRelease = nullptr; // caller is responsible for deleting this data 1.501 + CLIPFORMAT format = aFormat->cfFormat; 1.502 + switch(format) { 1.503 + 1.504 + // Someone is asking for plain or unicode text 1.505 + case CF_TEXT: 1.506 + case CF_UNICODETEXT: 1.507 + return GetText(df, *aFormat, *pSTM); 1.508 + 1.509 + // Some 3rd party apps that receive drag and drop files from the browser 1.510 + // window require support for this. 1.511 + case CF_HDROP: 1.512 + return GetFile(*aFormat, *pSTM); 1.513 + 1.514 + // Someone is asking for an image 1.515 + case CF_DIBV5: 1.516 + case CF_DIB: 1.517 + return GetDib(df, *aFormat, *pSTM); 1.518 + 1.519 + default: 1.520 + if ( format == fileDescriptorFlavorA ) 1.521 + return GetFileDescriptor ( *aFormat, *pSTM, false ); 1.522 + if ( format == fileDescriptorFlavorW ) 1.523 + return GetFileDescriptor ( *aFormat, *pSTM, true); 1.524 + if ( format == uniformResourceLocatorA ) 1.525 + return GetUniformResourceLocator( *aFormat, *pSTM, false); 1.526 + if ( format == uniformResourceLocatorW ) 1.527 + return GetUniformResourceLocator( *aFormat, *pSTM, true); 1.528 + if ( format == fileFlavor ) 1.529 + return GetFileContents ( *aFormat, *pSTM ); 1.530 + if ( format == PreferredDropEffect ) 1.531 + return GetPreferredDropEffect( *aFormat, *pSTM ); 1.532 + //PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.533 + // ("***** nsDataObj::GetData - Unknown format %u\n", format)); 1.534 + return GetText(df, *aFormat, *pSTM); 1.535 + } //switch 1.536 + } // if 1.537 + dfInx++; 1.538 + } // while 1.539 + 1.540 + return DATA_E_FORMATETC; 1.541 +} 1.542 + 1.543 +//----------------------------------------------------- 1.544 +STDMETHODIMP nsDataObj::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM) 1.545 +{ 1.546 + return E_FAIL; 1.547 +} 1.548 + 1.549 + 1.550 +//----------------------------------------------------- 1.551 +// Other objects querying to see if we support a 1.552 +// particular format 1.553 +//----------------------------------------------------- 1.554 +STDMETHODIMP nsDataObj::QueryGetData(LPFORMATETC pFE) 1.555 +{ 1.556 + // Arbitrary system formats are used for image feedback during drag 1.557 + // and drop. We are responsible for storing these internally during 1.558 + // drag operations. 1.559 + LPDATAENTRY pde; 1.560 + if (LookupArbitraryFormat(pFE, &pde, FALSE)) 1.561 + return S_OK; 1.562 + 1.563 + // Firefox internal formats 1.564 + ULONG count; 1.565 + FORMATETC fe; 1.566 + m_enumFE->Reset(); 1.567 + while (NOERROR == m_enumFE->Next(1, &fe, &count)) { 1.568 + if (fe.cfFormat == pFE->cfFormat) { 1.569 + return S_OK; 1.570 + } 1.571 + } 1.572 + return E_FAIL; 1.573 +} 1.574 + 1.575 +//----------------------------------------------------- 1.576 +STDMETHODIMP nsDataObj::GetCanonicalFormatEtc 1.577 + (LPFORMATETC pFEIn, LPFORMATETC pFEOut) 1.578 +{ 1.579 + return E_FAIL; 1.580 +} 1.581 + 1.582 +//----------------------------------------------------- 1.583 +STDMETHODIMP nsDataObj::SetData(LPFORMATETC aFormat, LPSTGMEDIUM aMedium, BOOL shouldRel) 1.584 +{ 1.585 + // Arbitrary system formats are used for image feedback during drag 1.586 + // and drop. We are responsible for storing these internally during 1.587 + // drag operations. 1.588 + LPDATAENTRY pde; 1.589 + if (LookupArbitraryFormat(aFormat, &pde, TRUE)) { 1.590 + // Release the old data the lookup handed us for this format. This 1.591 + // may have been set in CopyMediumData when we originally stored the 1.592 + // data. 1.593 + if (pde->stgm.tymed) { 1.594 + ReleaseStgMedium(&pde->stgm); 1.595 + memset(&pde->stgm, 0, sizeof(STGMEDIUM)); 1.596 + } 1.597 + 1.598 + bool result = true; 1.599 + if (shouldRel) { 1.600 + // If shouldRel is TRUE, the data object called owns the storage medium 1.601 + // after the call returns. Store the incoming data in our data array for 1.602 + // release when we are destroyed. This is the common case with arbitrary 1.603 + // data from explorer. 1.604 + pde->stgm = *aMedium; 1.605 + } else { 1.606 + // Copy the incoming data into our data array. (AFAICT, this never gets 1.607 + // called with arbitrary formats for drag images.) 1.608 + result = CopyMediumData(&pde->stgm, aMedium, aFormat, TRUE); 1.609 + } 1.610 + pde->fe.tymed = pde->stgm.tymed; 1.611 + 1.612 + return result ? S_OK : DV_E_TYMED; 1.613 + } 1.614 + 1.615 + if (shouldRel) 1.616 + ReleaseStgMedium(aMedium); 1.617 + 1.618 + return S_OK; 1.619 +} 1.620 + 1.621 +bool 1.622 +nsDataObj::LookupArbitraryFormat(FORMATETC *aFormat, LPDATAENTRY *aDataEntry, BOOL aAddorUpdate) 1.623 +{ 1.624 + *aDataEntry = nullptr; 1.625 + 1.626 + if (aFormat->ptd != nullptr) 1.627 + return false; 1.628 + 1.629 + // See if it's already in our list. If so return the data entry. 1.630 + for (uint32_t idx = 0; idx < mDataEntryList.Length(); idx++) { 1.631 + if (mDataEntryList[idx]->fe.cfFormat == aFormat->cfFormat && 1.632 + mDataEntryList[idx]->fe.dwAspect == aFormat->dwAspect && 1.633 + mDataEntryList[idx]->fe.lindex == aFormat->lindex) { 1.634 + if (aAddorUpdate || (mDataEntryList[idx]->fe.tymed & aFormat->tymed)) { 1.635 + // If the caller requests we update, or if the 1.636 + // medium type matches, return the entry. 1.637 + *aDataEntry = mDataEntryList[idx]; 1.638 + return true; 1.639 + } else { 1.640 + // Medium does not match, not found. 1.641 + return false; 1.642 + } 1.643 + } 1.644 + } 1.645 + 1.646 + if (!aAddorUpdate) 1.647 + return false; 1.648 + 1.649 + // Add another entry to mDataEntryList 1.650 + LPDATAENTRY dataEntry = (LPDATAENTRY)CoTaskMemAlloc(sizeof(DATAENTRY)); 1.651 + if (!dataEntry) 1.652 + return false; 1.653 + 1.654 + dataEntry->fe = *aFormat; 1.655 + *aDataEntry = dataEntry; 1.656 + memset(&dataEntry->stgm, 0, sizeof(STGMEDIUM)); 1.657 + 1.658 + // Add this to our IEnumFORMATETC impl. so we can return it when 1.659 + // it's requested. 1.660 + m_enumFE->AddFormatEtc(aFormat); 1.661 + 1.662 + // Store a copy internally in the arbitrary formats array. 1.663 + mDataEntryList.AppendElement(dataEntry); 1.664 + 1.665 + return true; 1.666 +} 1.667 + 1.668 +bool 1.669 +nsDataObj::CopyMediumData(STGMEDIUM *aMediumDst, STGMEDIUM *aMediumSrc, LPFORMATETC aFormat, BOOL aSetData) 1.670 +{ 1.671 + STGMEDIUM stgmOut = *aMediumSrc; 1.672 + 1.673 + switch (stgmOut.tymed) { 1.674 + case TYMED_ISTREAM: 1.675 + stgmOut.pstm->AddRef(); 1.676 + break; 1.677 + case TYMED_ISTORAGE: 1.678 + stgmOut.pstg->AddRef(); 1.679 + break; 1.680 + case TYMED_HGLOBAL: 1.681 + if (!aMediumSrc->pUnkForRelease) { 1.682 + if (aSetData) { 1.683 + if (aMediumSrc->tymed != TYMED_HGLOBAL) 1.684 + return false; 1.685 + stgmOut.hGlobal = OleDuplicateData(aMediumSrc->hGlobal, aFormat->cfFormat, 0); 1.686 + if (!stgmOut.hGlobal) 1.687 + return false; 1.688 + } else { 1.689 + // We are returning this data from LookupArbitraryFormat, indicate to the 1.690 + // shell we hold it and will free it. 1.691 + stgmOut.pUnkForRelease = static_cast<IDataObject*>(this); 1.692 + } 1.693 + } 1.694 + break; 1.695 + default: 1.696 + return false; 1.697 + } 1.698 + 1.699 + if (stgmOut.pUnkForRelease) 1.700 + stgmOut.pUnkForRelease->AddRef(); 1.701 + 1.702 + *aMediumDst = stgmOut; 1.703 + 1.704 + return true; 1.705 +} 1.706 + 1.707 +//----------------------------------------------------- 1.708 +STDMETHODIMP nsDataObj::EnumFormatEtc(DWORD dwDir, LPENUMFORMATETC *ppEnum) 1.709 +{ 1.710 + switch (dwDir) { 1.711 + case DATADIR_GET: 1.712 + m_enumFE->Clone(ppEnum); 1.713 + break; 1.714 + case DATADIR_SET: 1.715 + // fall through 1.716 + default: 1.717 + *ppEnum = nullptr; 1.718 + } // switch 1.719 + 1.720 + if (nullptr == *ppEnum) 1.721 + return E_FAIL; 1.722 + 1.723 + (*ppEnum)->Reset(); 1.724 + // Clone already AddRefed the result so don't addref it again. 1.725 + return NOERROR; 1.726 +} 1.727 + 1.728 +//----------------------------------------------------- 1.729 +STDMETHODIMP nsDataObj::DAdvise(LPFORMATETC pFE, DWORD dwFlags, 1.730 + LPADVISESINK pIAdviseSink, DWORD* pdwConn) 1.731 +{ 1.732 + return E_FAIL; 1.733 +} 1.734 + 1.735 + 1.736 +//----------------------------------------------------- 1.737 +STDMETHODIMP nsDataObj::DUnadvise(DWORD dwConn) 1.738 +{ 1.739 + return E_FAIL; 1.740 +} 1.741 + 1.742 +//----------------------------------------------------- 1.743 +STDMETHODIMP nsDataObj::EnumDAdvise(LPENUMSTATDATA *ppEnum) 1.744 +{ 1.745 + return E_FAIL; 1.746 +} 1.747 + 1.748 +// IAsyncOperation methods 1.749 +STDMETHODIMP nsDataObj::EndOperation(HRESULT hResult, 1.750 + IBindCtx *pbcReserved, 1.751 + DWORD dwEffects) 1.752 +{ 1.753 + mIsInOperation = FALSE; 1.754 + return S_OK; 1.755 +} 1.756 + 1.757 +STDMETHODIMP nsDataObj::GetAsyncMode(BOOL *pfIsOpAsync) 1.758 +{ 1.759 + *pfIsOpAsync = mIsAsyncMode; 1.760 + 1.761 + return S_OK; 1.762 +} 1.763 + 1.764 +STDMETHODIMP nsDataObj::InOperation(BOOL *pfInAsyncOp) 1.765 +{ 1.766 + *pfInAsyncOp = mIsInOperation; 1.767 + 1.768 + return S_OK; 1.769 +} 1.770 + 1.771 +STDMETHODIMP nsDataObj::SetAsyncMode(BOOL fDoOpAsync) 1.772 +{ 1.773 + mIsAsyncMode = fDoOpAsync; 1.774 + return S_OK; 1.775 +} 1.776 + 1.777 +STDMETHODIMP nsDataObj::StartOperation(IBindCtx *pbcReserved) 1.778 +{ 1.779 + mIsInOperation = TRUE; 1.780 + return S_OK; 1.781 +} 1.782 + 1.783 +//----------------------------------------------------- 1.784 +// GetData and SetData helper functions 1.785 +//----------------------------------------------------- 1.786 +HRESULT nsDataObj::AddSetFormat(FORMATETC& aFE) 1.787 +{ 1.788 + return S_OK; 1.789 +} 1.790 + 1.791 +//----------------------------------------------------- 1.792 +HRESULT nsDataObj::AddGetFormat(FORMATETC& aFE) 1.793 +{ 1.794 + return S_OK; 1.795 +} 1.796 + 1.797 +// 1.798 +// GetDIB 1.799 +// 1.800 +// Someone is asking for a bitmap. The data in the transferable will be a straight 1.801 +// imgIContainer, so just QI it. 1.802 +// 1.803 +HRESULT 1.804 +nsDataObj::GetDib(const nsACString& inFlavor, 1.805 + FORMATETC &aFormat, 1.806 + STGMEDIUM & aSTG) 1.807 +{ 1.808 + ULONG result = E_FAIL; 1.809 + uint32_t len = 0; 1.810 + nsCOMPtr<nsISupports> genericDataWrapper; 1.811 + mTransferable->GetTransferData(PromiseFlatCString(inFlavor).get(), getter_AddRefs(genericDataWrapper), &len); 1.812 + nsCOMPtr<imgIContainer> image ( do_QueryInterface(genericDataWrapper) ); 1.813 + if ( !image ) { 1.814 + // Check if the image was put in an nsISupportsInterfacePointer wrapper. 1.815 + // This might not be necessary any more, but could be useful for backwards 1.816 + // compatibility. 1.817 + nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericDataWrapper)); 1.818 + if ( ptr ) { 1.819 + nsCOMPtr<nsISupports> supports; 1.820 + ptr->GetData(getter_AddRefs(supports)); 1.821 + image = do_QueryInterface(supports); 1.822 + } 1.823 + } 1.824 + 1.825 + if ( image ) { 1.826 + // use the |nsImageToClipboard| helper class to build up a bitmap. We now own 1.827 + // the bits, and pass them back to the OS in |aSTG|. 1.828 + nsImageToClipboard converter(image, aFormat.cfFormat == CF_DIBV5); 1.829 + HANDLE bits = nullptr; 1.830 + nsresult rv = converter.GetPicture ( &bits ); 1.831 + if ( NS_SUCCEEDED(rv) && bits ) { 1.832 + aSTG.hGlobal = bits; 1.833 + aSTG.tymed = TYMED_HGLOBAL; 1.834 + result = S_OK; 1.835 + } 1.836 + } // if we have an image 1.837 + else 1.838 + NS_WARNING ( "Definitely not an image on clipboard" ); 1.839 + return result; 1.840 +} 1.841 + 1.842 + 1.843 + 1.844 +// 1.845 +// GetFileDescriptor 1.846 +// 1.847 + 1.848 +HRESULT 1.849 +nsDataObj :: GetFileDescriptor ( FORMATETC& aFE, STGMEDIUM& aSTG, bool aIsUnicode ) 1.850 +{ 1.851 + HRESULT res = S_OK; 1.852 + 1.853 + // How we handle this depends on if we're dealing with an internet 1.854 + // shortcut, since those are done under the covers. 1.855 + if (IsFlavourPresent(kFilePromiseMime) || 1.856 + IsFlavourPresent(kFileMime)) 1.857 + { 1.858 + if (aIsUnicode) 1.859 + return GetFileDescriptor_IStreamW(aFE, aSTG); 1.860 + else 1.861 + return GetFileDescriptor_IStreamA(aFE, aSTG); 1.862 + } 1.863 + else if (IsFlavourPresent(kURLMime)) 1.864 + { 1.865 + if ( aIsUnicode ) 1.866 + res = GetFileDescriptorInternetShortcutW ( aFE, aSTG ); 1.867 + else 1.868 + res = GetFileDescriptorInternetShortcutA ( aFE, aSTG ); 1.869 + } 1.870 + else 1.871 + NS_WARNING ( "Not yet implemented\n" ); 1.872 + 1.873 + return res; 1.874 +} // GetFileDescriptor 1.875 + 1.876 + 1.877 +// 1.878 +HRESULT 1.879 +nsDataObj :: GetFileContents ( FORMATETC& aFE, STGMEDIUM& aSTG ) 1.880 +{ 1.881 + HRESULT res = S_OK; 1.882 + 1.883 + // How we handle this depends on if we're dealing with an internet 1.884 + // shortcut, since those are done under the covers. 1.885 + if (IsFlavourPresent(kFilePromiseMime) || 1.886 + IsFlavourPresent(kFileMime)) 1.887 + return GetFileContents_IStream(aFE, aSTG); 1.888 + else if (IsFlavourPresent(kURLMime)) 1.889 + return GetFileContentsInternetShortcut ( aFE, aSTG ); 1.890 + else 1.891 + NS_WARNING ( "Not yet implemented\n" ); 1.892 + 1.893 + return res; 1.894 + 1.895 +} // GetFileContents 1.896 + 1.897 +// 1.898 +// Given a unicode string, we ensure that it contains only characters which are valid within 1.899 +// the file system. Remove all forbidden characters from the name, and completely disallow 1.900 +// any title that starts with a forbidden name and extension (e.g. "nul" is invalid, but 1.901 +// "nul." and "nul.txt" are also invalid and will cause problems). 1.902 +// 1.903 +// It would seem that this is more functionality suited to being in nsIFile. 1.904 +// 1.905 +static void 1.906 +MangleTextToValidFilename(nsString & aText) 1.907 +{ 1.908 + static const char* forbiddenNames[] = { 1.909 + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", 1.910 + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", 1.911 + "CON", "PRN", "AUX", "NUL", "CLOCK$" 1.912 + }; 1.913 + 1.914 + aText.StripChars(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS); 1.915 + aText.CompressWhitespace(true, true); 1.916 + uint32_t nameLen; 1.917 + for (size_t n = 0; n < ArrayLength(forbiddenNames); ++n) { 1.918 + nameLen = (uint32_t) strlen(forbiddenNames[n]); 1.919 + if (aText.EqualsIgnoreCase(forbiddenNames[n], nameLen)) { 1.920 + // invalid name is either the entire string, or a prefix with a period 1.921 + if (aText.Length() == nameLen || aText.CharAt(nameLen) == char16_t('.')) { 1.922 + aText.Truncate(); 1.923 + break; 1.924 + } 1.925 + } 1.926 + } 1.927 +} 1.928 + 1.929 +// 1.930 +// Given a unicode string, convert it down to a valid local charset filename 1.931 +// with the supplied extension. This ensures that we do not cut MBCS characters 1.932 +// in the middle. 1.933 +// 1.934 +// It would seem that this is more functionality suited to being in nsIFile. 1.935 +// 1.936 +static bool 1.937 +CreateFilenameFromTextA(nsString & aText, const char * aExtension, 1.938 + char * aFilename, uint32_t aFilenameLen) 1.939 +{ 1.940 + // ensure that the supplied name doesn't have invalid characters. If 1.941 + // a valid mangled filename couldn't be created then it will leave the 1.942 + // text empty. 1.943 + MangleTextToValidFilename(aText); 1.944 + if (aText.IsEmpty()) 1.945 + return false; 1.946 + 1.947 + // repeatably call WideCharToMultiByte as long as the title doesn't fit in the buffer 1.948 + // available to us. Continually reduce the length of the source title until the MBCS 1.949 + // version will fit in the buffer with room for the supplied extension. Doing it this 1.950 + // way ensures that even in MBCS environments there will be a valid MBCS filename of 1.951 + // the correct length. 1.952 + int maxUsableFilenameLen = aFilenameLen - strlen(aExtension) - 1; // space for ext + null byte 1.953 + int currLen, textLen = (int) std::min(aText.Length(), aFilenameLen); 1.954 + char defaultChar = '_'; 1.955 + do { 1.956 + currLen = WideCharToMultiByte(CP_ACP, 1.957 + WC_COMPOSITECHECK|WC_DEFAULTCHAR, 1.958 + aText.get(), textLen--, aFilename, maxUsableFilenameLen, &defaultChar, nullptr); 1.959 + } 1.960 + while (currLen == 0 && textLen > 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER); 1.961 + if (currLen > 0 && textLen > 0) { 1.962 + strcpy(&aFilename[currLen], aExtension); 1.963 + return true; 1.964 + } 1.965 + else { 1.966 + // empty names aren't permitted 1.967 + return false; 1.968 + } 1.969 +} 1.970 + 1.971 +static bool 1.972 +CreateFilenameFromTextW(nsString & aText, const wchar_t * aExtension, 1.973 + wchar_t * aFilename, uint32_t aFilenameLen) 1.974 +{ 1.975 + // ensure that the supplied name doesn't have invalid characters. If 1.976 + // a valid mangled filename couldn't be created then it will leave the 1.977 + // text empty. 1.978 + MangleTextToValidFilename(aText); 1.979 + if (aText.IsEmpty()) 1.980 + return false; 1.981 + 1.982 + const int extensionLen = wcslen(aExtension); 1.983 + if (aText.Length() + extensionLen + 1 > aFilenameLen) 1.984 + aText.Truncate(aFilenameLen - extensionLen - 1); 1.985 + wcscpy(&aFilename[0], aText.get()); 1.986 + wcscpy(&aFilename[aText.Length()], aExtension); 1.987 + return true; 1.988 +} 1.989 + 1.990 +#define PAGEINFO_PROPERTIES "chrome://navigator/locale/pageInfo.properties" 1.991 + 1.992 +static bool 1.993 +GetLocalizedString(const char16_t * aName, nsXPIDLString & aString) 1.994 +{ 1.995 + nsCOMPtr<nsIStringBundleService> stringService = 1.996 + mozilla::services::GetStringBundleService(); 1.997 + if (!stringService) 1.998 + return false; 1.999 + 1.1000 + nsCOMPtr<nsIStringBundle> stringBundle; 1.1001 + nsresult rv = stringService->CreateBundle(PAGEINFO_PROPERTIES, 1.1002 + getter_AddRefs(stringBundle)); 1.1003 + if (NS_FAILED(rv)) 1.1004 + return false; 1.1005 + 1.1006 + rv = stringBundle->GetStringFromName(aName, getter_Copies(aString)); 1.1007 + return NS_SUCCEEDED(rv); 1.1008 +} 1.1009 + 1.1010 +// 1.1011 +// GetFileDescriptorInternetShortcut 1.1012 +// 1.1013 +// Create the special format for an internet shortcut and build up the data 1.1014 +// structures the shell is expecting. 1.1015 +// 1.1016 +HRESULT 1.1017 +nsDataObj :: GetFileDescriptorInternetShortcutA ( FORMATETC& aFE, STGMEDIUM& aSTG ) 1.1018 +{ 1.1019 + // get the title of the shortcut 1.1020 + nsAutoString title; 1.1021 + if ( NS_FAILED(ExtractShortcutTitle(title)) ) 1.1022 + return E_OUTOFMEMORY; 1.1023 + 1.1024 + HGLOBAL fileGroupDescHandle = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE,sizeof(FILEGROUPDESCRIPTORA)); 1.1025 + if (!fileGroupDescHandle) 1.1026 + return E_OUTOFMEMORY; 1.1027 + 1.1028 + LPFILEGROUPDESCRIPTORA fileGroupDescA = reinterpret_cast<LPFILEGROUPDESCRIPTORA>(::GlobalLock(fileGroupDescHandle)); 1.1029 + if (!fileGroupDescA) { 1.1030 + ::GlobalFree(fileGroupDescHandle); 1.1031 + return E_OUTOFMEMORY; 1.1032 + } 1.1033 + 1.1034 + // get a valid filename in the following order: 1) from the page title, 1.1035 + // 2) localized string for an untitled page, 3) just use "Untitled.URL" 1.1036 + if (!CreateFilenameFromTextA(title, ".URL", 1.1037 + fileGroupDescA->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) { 1.1038 + nsXPIDLString untitled; 1.1039 + if (!GetLocalizedString(MOZ_UTF16("noPageTitle"), untitled) || 1.1040 + !CreateFilenameFromTextA(untitled, ".URL", 1.1041 + fileGroupDescA->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) { 1.1042 + strcpy(fileGroupDescA->fgd[0].cFileName, "Untitled.URL"); 1.1043 + } 1.1044 + } 1.1045 + 1.1046 + // one file in the file block 1.1047 + fileGroupDescA->cItems = 1; 1.1048 + fileGroupDescA->fgd[0].dwFlags = FD_LINKUI; 1.1049 + 1.1050 + ::GlobalUnlock( fileGroupDescHandle ); 1.1051 + aSTG.hGlobal = fileGroupDescHandle; 1.1052 + aSTG.tymed = TYMED_HGLOBAL; 1.1053 + 1.1054 + return S_OK; 1.1055 +} // GetFileDescriptorInternetShortcutA 1.1056 + 1.1057 +HRESULT 1.1058 +nsDataObj :: GetFileDescriptorInternetShortcutW ( FORMATETC& aFE, STGMEDIUM& aSTG ) 1.1059 +{ 1.1060 + // get the title of the shortcut 1.1061 + nsAutoString title; 1.1062 + if ( NS_FAILED(ExtractShortcutTitle(title)) ) 1.1063 + return E_OUTOFMEMORY; 1.1064 + 1.1065 + HGLOBAL fileGroupDescHandle = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE,sizeof(FILEGROUPDESCRIPTORW)); 1.1066 + if (!fileGroupDescHandle) 1.1067 + return E_OUTOFMEMORY; 1.1068 + 1.1069 + LPFILEGROUPDESCRIPTORW fileGroupDescW = reinterpret_cast<LPFILEGROUPDESCRIPTORW>(::GlobalLock(fileGroupDescHandle)); 1.1070 + if (!fileGroupDescW) { 1.1071 + ::GlobalFree(fileGroupDescHandle); 1.1072 + return E_OUTOFMEMORY; 1.1073 + } 1.1074 + 1.1075 + // get a valid filename in the following order: 1) from the page title, 1.1076 + // 2) localized string for an untitled page, 3) just use "Untitled.URL" 1.1077 + if (!CreateFilenameFromTextW(title, L".URL", 1.1078 + fileGroupDescW->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) { 1.1079 + nsXPIDLString untitled; 1.1080 + if (!GetLocalizedString(MOZ_UTF16("noPageTitle"), untitled) || 1.1081 + !CreateFilenameFromTextW(untitled, L".URL", 1.1082 + fileGroupDescW->fgd[0].cFileName, NS_MAX_FILEDESCRIPTOR)) { 1.1083 + wcscpy(fileGroupDescW->fgd[0].cFileName, L"Untitled.URL"); 1.1084 + } 1.1085 + } 1.1086 + 1.1087 + // one file in the file block 1.1088 + fileGroupDescW->cItems = 1; 1.1089 + fileGroupDescW->fgd[0].dwFlags = FD_LINKUI; 1.1090 + 1.1091 + ::GlobalUnlock( fileGroupDescHandle ); 1.1092 + aSTG.hGlobal = fileGroupDescHandle; 1.1093 + aSTG.tymed = TYMED_HGLOBAL; 1.1094 + 1.1095 + return S_OK; 1.1096 +} // GetFileDescriptorInternetShortcutW 1.1097 + 1.1098 + 1.1099 +// 1.1100 +// GetFileContentsInternetShortcut 1.1101 +// 1.1102 +// Create the special format for an internet shortcut and build up the data 1.1103 +// structures the shell is expecting. 1.1104 +// 1.1105 +HRESULT 1.1106 +nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG ) 1.1107 +{ 1.1108 + static const char * kShellIconPref = "browser.shell.shortcutFavicons"; 1.1109 + nsAutoString url; 1.1110 + if ( NS_FAILED(ExtractShortcutURL(url)) ) 1.1111 + return E_OUTOFMEMORY; 1.1112 + 1.1113 + // will need to change if we ever support iDNS 1.1114 + nsAutoCString asciiUrl; 1.1115 + LossyCopyUTF16toASCII(url, asciiUrl); 1.1116 + 1.1117 + nsCOMPtr<nsIFile> icoFile; 1.1118 + nsCOMPtr<nsIURI> aUri; 1.1119 + NS_NewURI(getter_AddRefs(aUri), url); 1.1120 + 1.1121 + const char *shortcutFormatStr; 1.1122 + int totalLen; 1.1123 + nsCString path; 1.1124 + if (!Preferences::GetBool(kShellIconPref, true) || 1.1125 + !IsVistaOrLater()) { 1.1126 + shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n"; 1.1127 + const int formatLen = strlen(shortcutFormatStr) - 2; // don't include %s 1.1128 + totalLen = formatLen + asciiUrl.Length(); // don't include null character 1.1129 + } else { 1.1130 + nsCOMPtr<nsIFile> icoFile; 1.1131 + nsCOMPtr<nsIURI> aUri; 1.1132 + NS_NewURI(getter_AddRefs(aUri), url); 1.1133 + 1.1134 + nsAutoString aUriHash; 1.1135 + 1.1136 + mozilla::widget::FaviconHelper::ObtainCachedIconFile(aUri, aUriHash, mIOThread, true); 1.1137 + 1.1138 + nsresult rv = mozilla::widget::FaviconHelper::GetOutputIconPath(aUri, icoFile, true); 1.1139 + NS_ENSURE_SUCCESS(rv, E_FAIL); 1.1140 + rv = icoFile->GetNativePath(path); 1.1141 + NS_ENSURE_SUCCESS(rv, E_FAIL); 1.1142 + 1.1143 + shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n" 1.1144 + "IDList=\r\nHotKey=0\r\nIconFile=%s\r\n" 1.1145 + "IconIndex=0\r\n"; 1.1146 + const int formatLen = strlen(shortcutFormatStr) - 2 * 2; // no %s twice 1.1147 + totalLen = formatLen + asciiUrl.Length() + 1.1148 + path.Length(); // we don't want a null character on the end 1.1149 + } 1.1150 + 1.1151 + // create a global memory area and build up the file contents w/in it 1.1152 + HGLOBAL hGlobalMemory = ::GlobalAlloc(GMEM_SHARE, totalLen); 1.1153 + if ( !hGlobalMemory ) 1.1154 + return E_OUTOFMEMORY; 1.1155 + 1.1156 + char* contents = reinterpret_cast<char*>(::GlobalLock(hGlobalMemory)); 1.1157 + if ( !contents ) { 1.1158 + ::GlobalFree( hGlobalMemory ); 1.1159 + return E_OUTOFMEMORY; 1.1160 + } 1.1161 + 1.1162 + //NOTE: we intentionally use the Microsoft version of snprintf here because it does NOT null 1.1163 + // terminate strings which reach the maximum size of the buffer. Since we know that the 1.1164 + // formatted length here is totalLen, this call to _snprintf will format the string into 1.1165 + // the buffer without appending the null character. 1.1166 + 1.1167 + if (!Preferences::GetBool(kShellIconPref, true)) { 1.1168 + _snprintf(contents, totalLen, shortcutFormatStr, asciiUrl.get()); 1.1169 + } else { 1.1170 + _snprintf(contents, totalLen, shortcutFormatStr, asciiUrl.get(), path.get()); 1.1171 + } 1.1172 + 1.1173 + ::GlobalUnlock(hGlobalMemory); 1.1174 + aSTG.hGlobal = hGlobalMemory; 1.1175 + aSTG.tymed = TYMED_HGLOBAL; 1.1176 + 1.1177 + return S_OK; 1.1178 +} // GetFileContentsInternetShortcut 1.1179 + 1.1180 +// check if specified flavour is present in the transferable 1.1181 +bool nsDataObj :: IsFlavourPresent(const char *inFlavour) 1.1182 +{ 1.1183 + bool retval = false; 1.1184 + NS_ENSURE_TRUE(mTransferable, false); 1.1185 + 1.1186 + // get the list of flavors available in the transferable 1.1187 + nsCOMPtr<nsISupportsArray> flavorList; 1.1188 + mTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); 1.1189 + NS_ENSURE_TRUE(flavorList, false); 1.1190 + 1.1191 + // try to find requested flavour 1.1192 + uint32_t cnt; 1.1193 + flavorList->Count(&cnt); 1.1194 + for (uint32_t i = 0; i < cnt; ++i) { 1.1195 + nsCOMPtr<nsISupports> genericFlavor; 1.1196 + flavorList->GetElementAt (i, getter_AddRefs(genericFlavor)); 1.1197 + nsCOMPtr<nsISupportsCString> currentFlavor (do_QueryInterface(genericFlavor)); 1.1198 + if (currentFlavor) { 1.1199 + nsAutoCString flavorStr; 1.1200 + currentFlavor->GetData(flavorStr); 1.1201 + if (flavorStr.Equals(inFlavour)) { 1.1202 + retval = true; // found it! 1.1203 + break; 1.1204 + } 1.1205 + } 1.1206 + } // for each flavor 1.1207 + 1.1208 + return retval; 1.1209 +} 1.1210 + 1.1211 +HRESULT nsDataObj::GetPreferredDropEffect ( FORMATETC& aFE, STGMEDIUM& aSTG ) 1.1212 +{ 1.1213 + HRESULT res = S_OK; 1.1214 + aSTG.tymed = TYMED_HGLOBAL; 1.1215 + aSTG.pUnkForRelease = nullptr; 1.1216 + HGLOBAL hGlobalMemory = nullptr; 1.1217 + hGlobalMemory = ::GlobalAlloc(GMEM_MOVEABLE, sizeof(DWORD)); 1.1218 + if (hGlobalMemory) { 1.1219 + DWORD* pdw = (DWORD*) GlobalLock(hGlobalMemory); 1.1220 + // The PreferredDropEffect clipboard format is only registered if a drag/drop 1.1221 + // of an image happens from Mozilla to the desktop. We want its value 1.1222 + // to be DROPEFFECT_MOVE in that case so that the file is moved from the 1.1223 + // temporary location, not copied. 1.1224 + // This value should, ideally, be set on the data object via SetData() but 1.1225 + // our IDataObject implementation doesn't implement SetData. It adds data 1.1226 + // to the data object lazily only when the drop target asks for it. 1.1227 + *pdw = (DWORD) DROPEFFECT_MOVE; 1.1228 + GlobalUnlock(hGlobalMemory); 1.1229 + } 1.1230 + else { 1.1231 + res = E_OUTOFMEMORY; 1.1232 + } 1.1233 + aSTG.hGlobal = hGlobalMemory; 1.1234 + return res; 1.1235 +} 1.1236 + 1.1237 +//----------------------------------------------------- 1.1238 +HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGMEDIUM& aSTG) 1.1239 +{ 1.1240 + void* data = nullptr; 1.1241 + uint32_t len; 1.1242 + 1.1243 + // if someone asks for text/plain, look up text/unicode instead in the transferable. 1.1244 + const char* flavorStr; 1.1245 + const nsPromiseFlatCString& flat = PromiseFlatCString(aDataFlavor); 1.1246 + if ( aDataFlavor.Equals("text/plain") ) 1.1247 + flavorStr = kUnicodeMime; 1.1248 + else 1.1249 + flavorStr = flat.get(); 1.1250 + 1.1251 + // NOTE: CreateDataFromPrimitive creates new memory, that needs to be deleted 1.1252 + nsCOMPtr<nsISupports> genericDataWrapper; 1.1253 + mTransferable->GetTransferData(flavorStr, getter_AddRefs(genericDataWrapper), &len); 1.1254 + if ( !len ) 1.1255 + return E_FAIL; 1.1256 + nsPrimitiveHelpers::CreateDataFromPrimitive ( flavorStr, genericDataWrapper, &data, len ); 1.1257 + if ( !data ) 1.1258 + return E_FAIL; 1.1259 + 1.1260 + HGLOBAL hGlobalMemory = nullptr; 1.1261 + 1.1262 + aSTG.tymed = TYMED_HGLOBAL; 1.1263 + aSTG.pUnkForRelease = nullptr; 1.1264 + 1.1265 + // We play games under the hood and advertise flavors that we know we 1.1266 + // can support, only they require a bit of conversion or munging of the data. 1.1267 + // Do that here. 1.1268 + // 1.1269 + // The transferable gives us data that is null-terminated, but this isn't reflected in 1.1270 + // the |len| parameter. Windoze apps expect this null to be there so bump our data buffer 1.1271 + // by the appropriate size to account for the null (one char for CF_TEXT, one char16_t for 1.1272 + // CF_UNICODETEXT). 1.1273 + DWORD allocLen = (DWORD)len; 1.1274 + if ( aFE.cfFormat == CF_TEXT ) { 1.1275 + // Someone is asking for text/plain; convert the unicode (assuming it's present) 1.1276 + // to text with the correct platform encoding. 1.1277 + char* plainTextData = nullptr; 1.1278 + char16_t* castedUnicode = reinterpret_cast<char16_t*>(data); 1.1279 + int32_t plainTextLen = 0; 1.1280 + nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText ( castedUnicode, len / 2, &plainTextData, &plainTextLen ); 1.1281 + 1.1282 + // replace the unicode data with our plaintext data. Recall that |plainTextLen| doesn't include 1.1283 + // the null in the length. 1.1284 + nsMemory::Free(data); 1.1285 + if ( plainTextData ) { 1.1286 + data = plainTextData; 1.1287 + allocLen = plainTextLen + sizeof(char); 1.1288 + } 1.1289 + else { 1.1290 + NS_WARNING ( "Oh no, couldn't convert unicode to plain text" ); 1.1291 + return S_OK; 1.1292 + } 1.1293 + } 1.1294 + else if ( aFE.cfFormat == nsClipboard::CF_HTML ) { 1.1295 + // Someone is asking for win32's HTML flavor. Convert our html fragment 1.1296 + // from unicode to UTF-8 then put it into a format specified by msft. 1.1297 + NS_ConvertUTF16toUTF8 converter ( reinterpret_cast<char16_t*>(data) ); 1.1298 + char* utf8HTML = nullptr; 1.1299 + nsresult rv = BuildPlatformHTML ( converter.get(), &utf8HTML ); // null terminates 1.1300 + 1.1301 + nsMemory::Free(data); 1.1302 + if ( NS_SUCCEEDED(rv) && utf8HTML ) { 1.1303 + // replace the unicode data with our HTML data. Don't forget the null. 1.1304 + data = utf8HTML; 1.1305 + allocLen = strlen(utf8HTML) + sizeof(char); 1.1306 + } 1.1307 + else { 1.1308 + NS_WARNING ( "Oh no, couldn't convert to HTML" ); 1.1309 + return S_OK; 1.1310 + } 1.1311 + } 1.1312 + else { 1.1313 + // we assume that any data that isn't caught above is unicode. This may 1.1314 + // be an erroneous assumption, but is true so far. 1.1315 + allocLen += sizeof(char16_t); 1.1316 + } 1.1317 + 1.1318 + hGlobalMemory = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, allocLen); 1.1319 + 1.1320 + // Copy text to Global Memory Area 1.1321 + if ( hGlobalMemory ) { 1.1322 + char* dest = reinterpret_cast<char*>(GlobalLock(hGlobalMemory)); 1.1323 + char* source = reinterpret_cast<char*>(data); 1.1324 + memcpy ( dest, source, allocLen ); // copies the null as well 1.1325 + GlobalUnlock(hGlobalMemory); 1.1326 + } 1.1327 + aSTG.hGlobal = hGlobalMemory; 1.1328 + 1.1329 + // Now, delete the memory that was created by CreateDataFromPrimitive (or our text/plain data) 1.1330 + nsMemory::Free(data); 1.1331 + 1.1332 + return S_OK; 1.1333 +} 1.1334 + 1.1335 +//----------------------------------------------------- 1.1336 +HRESULT nsDataObj::GetFile(FORMATETC& aFE, STGMEDIUM& aSTG) 1.1337 +{ 1.1338 + uint32_t dfInx = 0; 1.1339 + ULONG count; 1.1340 + FORMATETC fe; 1.1341 + m_enumFE->Reset(); 1.1342 + while (NOERROR == m_enumFE->Next(1, &fe, &count) 1.1343 + && dfInx < mDataFlavors.Length()) { 1.1344 + if (mDataFlavors[dfInx].EqualsLiteral(kNativeImageMime)) 1.1345 + return DropImage(aFE, aSTG); 1.1346 + if (mDataFlavors[dfInx].EqualsLiteral(kFileMime)) 1.1347 + return DropFile(aFE, aSTG); 1.1348 + if (mDataFlavors[dfInx].EqualsLiteral(kFilePromiseMime)) 1.1349 + return DropTempFile(aFE, aSTG); 1.1350 + dfInx++; 1.1351 + } 1.1352 + return E_FAIL; 1.1353 +} 1.1354 + 1.1355 +HRESULT nsDataObj::DropFile(FORMATETC& aFE, STGMEDIUM& aSTG) 1.1356 +{ 1.1357 + nsresult rv; 1.1358 + uint32_t len = 0; 1.1359 + nsCOMPtr<nsISupports> genericDataWrapper; 1.1360 + 1.1361 + mTransferable->GetTransferData(kFileMime, getter_AddRefs(genericDataWrapper), 1.1362 + &len); 1.1363 + nsCOMPtr<nsIFile> file ( do_QueryInterface(genericDataWrapper) ); 1.1364 + 1.1365 + if (!file) 1.1366 + { 1.1367 + nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericDataWrapper)); 1.1368 + if (ptr) { 1.1369 + nsCOMPtr<nsISupports> supports; 1.1370 + ptr->GetData(getter_AddRefs(supports)); 1.1371 + file = do_QueryInterface(supports); 1.1372 + } 1.1373 + } 1.1374 + 1.1375 + if (!file) 1.1376 + return E_FAIL; 1.1377 + 1.1378 + aSTG.tymed = TYMED_HGLOBAL; 1.1379 + aSTG.pUnkForRelease = nullptr; 1.1380 + 1.1381 + nsAutoString path; 1.1382 + rv = file->GetPath(path); 1.1383 + if (NS_FAILED(rv)) 1.1384 + return E_FAIL; 1.1385 + 1.1386 + uint32_t allocLen = path.Length() + 2; 1.1387 + HGLOBAL hGlobalMemory = nullptr; 1.1388 + char16_t *dest; 1.1389 + 1.1390 + hGlobalMemory = GlobalAlloc(GMEM_MOVEABLE, sizeof(DROPFILES) + 1.1391 + allocLen * sizeof(char16_t)); 1.1392 + if (!hGlobalMemory) 1.1393 + return E_FAIL; 1.1394 + 1.1395 + DROPFILES* pDropFile = (DROPFILES*)GlobalLock(hGlobalMemory); 1.1396 + 1.1397 + // First, populate the drop file structure 1.1398 + pDropFile->pFiles = sizeof(DROPFILES); //Offset to start of file name string 1.1399 + pDropFile->fNC = 0; 1.1400 + pDropFile->pt.x = 0; 1.1401 + pDropFile->pt.y = 0; 1.1402 + pDropFile->fWide = TRUE; 1.1403 + 1.1404 + // Copy the filename right after the DROPFILES structure 1.1405 + dest = (char16_t*)(((char*)pDropFile) + pDropFile->pFiles); 1.1406 + memcpy(dest, path.get(), (allocLen - 1) * sizeof(char16_t)); 1.1407 + 1.1408 + // Two null characters are needed at the end of the file name. 1.1409 + // Lookup the CF_HDROP shell clipboard format for more info. 1.1410 + // Add the second null character right after the first one. 1.1411 + dest[allocLen - 1] = L'\0'; 1.1412 + 1.1413 + GlobalUnlock(hGlobalMemory); 1.1414 + 1.1415 + aSTG.hGlobal = hGlobalMemory; 1.1416 + 1.1417 + return S_OK; 1.1418 +} 1.1419 + 1.1420 +HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG) 1.1421 +{ 1.1422 + nsresult rv; 1.1423 + if (!mCachedTempFile) { 1.1424 + uint32_t len = 0; 1.1425 + nsCOMPtr<nsISupports> genericDataWrapper; 1.1426 + 1.1427 + mTransferable->GetTransferData(kNativeImageMime, getter_AddRefs(genericDataWrapper), &len); 1.1428 + nsCOMPtr<imgIContainer> image(do_QueryInterface(genericDataWrapper)); 1.1429 + 1.1430 + if (!image) { 1.1431 + // Check if the image was put in an nsISupportsInterfacePointer wrapper. 1.1432 + // This might not be necessary any more, but could be useful for backwards 1.1433 + // compatibility. 1.1434 + nsCOMPtr<nsISupportsInterfacePointer> ptr(do_QueryInterface(genericDataWrapper)); 1.1435 + if (ptr) { 1.1436 + nsCOMPtr<nsISupports> supports; 1.1437 + ptr->GetData(getter_AddRefs(supports)); 1.1438 + image = do_QueryInterface(supports); 1.1439 + } 1.1440 + } 1.1441 + 1.1442 + if (!image) 1.1443 + return E_FAIL; 1.1444 + 1.1445 + // Use the clipboard helper class to build up a memory bitmap. 1.1446 + nsImageToClipboard converter(image); 1.1447 + HANDLE bits = nullptr; 1.1448 + rv = converter.GetPicture(&bits); // Clipboard routines return a global handle we own. 1.1449 + 1.1450 + if (NS_FAILED(rv) || !bits) 1.1451 + return E_FAIL; 1.1452 + 1.1453 + // We now own these bits! 1.1454 + uint32_t bitmapSize = GlobalSize(bits); 1.1455 + if (!bitmapSize) { 1.1456 + GlobalFree(bits); 1.1457 + return E_FAIL; 1.1458 + } 1.1459 + 1.1460 + // Save the bitmap to a temporary location. 1.1461 + nsCOMPtr<nsIFile> dropFile; 1.1462 + rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dropFile)); 1.1463 + if (!dropFile) { 1.1464 + GlobalFree(bits); 1.1465 + return E_FAIL; 1.1466 + } 1.1467 + 1.1468 + // Filename must be random so as not to confuse apps like 1.1469 + // Photoshop which handle multiple drags into a single window. 1.1470 + char buf[13]; 1.1471 + nsCString filename; 1.1472 + NS_MakeRandomString(buf, 8); 1.1473 + memcpy(buf+8, ".bmp", 5); 1.1474 + filename.Append(nsDependentCString(buf, 12)); 1.1475 + dropFile->AppendNative(filename); 1.1476 + rv = dropFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0660); 1.1477 + if (NS_FAILED(rv)) { 1.1478 + GlobalFree(bits); 1.1479 + return E_FAIL; 1.1480 + } 1.1481 + 1.1482 + // Cache the temp file so we can delete it later and so 1.1483 + // it doesn't get recreated over and over on multiple calls 1.1484 + // which does occur from windows shell. 1.1485 + dropFile->Clone(getter_AddRefs(mCachedTempFile)); 1.1486 + 1.1487 + // Write the data to disk. 1.1488 + nsCOMPtr<nsIOutputStream> outStream; 1.1489 + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), dropFile); 1.1490 + if (NS_FAILED(rv)) { 1.1491 + GlobalFree(bits); 1.1492 + return E_FAIL; 1.1493 + } 1.1494 + 1.1495 + char * bm = (char *)GlobalLock(bits); 1.1496 + 1.1497 + BITMAPFILEHEADER fileHdr; 1.1498 + BITMAPINFOHEADER *bmpHdr = (BITMAPINFOHEADER*)bm; 1.1499 + 1.1500 + fileHdr.bfType = ((WORD) ('M' << 8) | 'B'); 1.1501 + fileHdr.bfSize = GlobalSize (bits) + sizeof(fileHdr); 1.1502 + fileHdr.bfReserved1 = 0; 1.1503 + fileHdr.bfReserved2 = 0; 1.1504 + fileHdr.bfOffBits = (DWORD) (sizeof(fileHdr) + bmpHdr->biSize); 1.1505 + 1.1506 + uint32_t writeCount = 0; 1.1507 + if (NS_FAILED(outStream->Write((const char *)&fileHdr, sizeof(fileHdr), &writeCount)) || 1.1508 + NS_FAILED(outStream->Write((const char *)bm, bitmapSize, &writeCount))) 1.1509 + rv = NS_ERROR_FAILURE; 1.1510 + 1.1511 + outStream->Close(); 1.1512 + 1.1513 + GlobalUnlock(bits); 1.1514 + GlobalFree(bits); 1.1515 + 1.1516 + if (NS_FAILED(rv)) 1.1517 + return E_FAIL; 1.1518 + } 1.1519 + 1.1520 + // Pass the file name back to the drop target so that it can access the file. 1.1521 + nsAutoString path; 1.1522 + rv = mCachedTempFile->GetPath(path); 1.1523 + if (NS_FAILED(rv)) 1.1524 + return E_FAIL; 1.1525 + 1.1526 + // Two null characters are needed to terminate the file name list. 1.1527 + HGLOBAL hGlobalMemory = nullptr; 1.1528 + 1.1529 + uint32_t allocLen = path.Length() + 2; 1.1530 + 1.1531 + aSTG.tymed = TYMED_HGLOBAL; 1.1532 + aSTG.pUnkForRelease = nullptr; 1.1533 + 1.1534 + hGlobalMemory = GlobalAlloc(GMEM_MOVEABLE, sizeof(DROPFILES) + allocLen * sizeof(char16_t)); 1.1535 + if (!hGlobalMemory) 1.1536 + return E_FAIL; 1.1537 + 1.1538 + DROPFILES* pDropFile = (DROPFILES*)GlobalLock(hGlobalMemory); 1.1539 + 1.1540 + // First, populate the drop file structure. 1.1541 + pDropFile->pFiles = sizeof(DROPFILES); // Offset to start of file name char array. 1.1542 + pDropFile->fNC = 0; 1.1543 + pDropFile->pt.x = 0; 1.1544 + pDropFile->pt.y = 0; 1.1545 + pDropFile->fWide = TRUE; 1.1546 + 1.1547 + // Copy the filename right after the DROPFILES structure. 1.1548 + char16_t* dest = (char16_t*)(((char*)pDropFile) + pDropFile->pFiles); 1.1549 + memcpy(dest, path.get(), (allocLen - 1) * sizeof(char16_t)); // Copies the null character in path as well. 1.1550 + 1.1551 + // Two null characters are needed at the end of the file name. 1.1552 + // Lookup the CF_HDROP shell clipboard format for more info. 1.1553 + // Add the second null character right after the first one. 1.1554 + dest[allocLen - 1] = L'\0'; 1.1555 + 1.1556 + GlobalUnlock(hGlobalMemory); 1.1557 + 1.1558 + aSTG.hGlobal = hGlobalMemory; 1.1559 + 1.1560 + return S_OK; 1.1561 +} 1.1562 + 1.1563 +HRESULT nsDataObj::DropTempFile(FORMATETC& aFE, STGMEDIUM& aSTG) 1.1564 +{ 1.1565 + nsresult rv; 1.1566 + if (!mCachedTempFile) { 1.1567 + // Tempfile will need a temporary location. 1.1568 + nsCOMPtr<nsIFile> dropFile; 1.1569 + rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dropFile)); 1.1570 + if (!dropFile) 1.1571 + return E_FAIL; 1.1572 + 1.1573 + // Filename must be random 1.1574 + nsCString filename; 1.1575 + nsAutoString wideFileName; 1.1576 + nsCOMPtr<nsIURI> sourceURI; 1.1577 + HRESULT res; 1.1578 + res = GetDownloadDetails(getter_AddRefs(sourceURI), 1.1579 + wideFileName); 1.1580 + if (FAILED(res)) 1.1581 + return res; 1.1582 + NS_UTF16ToCString(wideFileName, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, filename); 1.1583 + 1.1584 + dropFile->AppendNative(filename); 1.1585 + rv = dropFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0660); 1.1586 + if (NS_FAILED(rv)) 1.1587 + return E_FAIL; 1.1588 + 1.1589 + // Cache the temp file so we can delete it later and so 1.1590 + // it doesn't get recreated over and over on multiple calls 1.1591 + // which does occur from windows shell. 1.1592 + dropFile->Clone(getter_AddRefs(mCachedTempFile)); 1.1593 + 1.1594 + // Write the data to disk. 1.1595 + nsCOMPtr<nsIOutputStream> outStream; 1.1596 + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), dropFile); 1.1597 + if (NS_FAILED(rv)) 1.1598 + return E_FAIL; 1.1599 + 1.1600 + IStream *pStream = nullptr; 1.1601 + nsDataObj::CreateStream(&pStream); 1.1602 + NS_ENSURE_TRUE(pStream, E_FAIL); 1.1603 + 1.1604 + char buffer[512]; 1.1605 + ULONG readCount = 0; 1.1606 + uint32_t writeCount = 0; 1.1607 + while (1) { 1.1608 + HRESULT hres = pStream->Read(buffer, sizeof(buffer), &readCount); 1.1609 + if (FAILED(hres)) 1.1610 + return E_FAIL; 1.1611 + if (readCount == 0) 1.1612 + break; 1.1613 + rv = outStream->Write(buffer, readCount, &writeCount); 1.1614 + if (NS_FAILED(rv)) 1.1615 + return E_FAIL; 1.1616 + } 1.1617 + outStream->Close(); 1.1618 + pStream->Release(); 1.1619 + } 1.1620 + 1.1621 + // Pass the file name back to the drop target so that it can access the file. 1.1622 + nsAutoString path; 1.1623 + rv = mCachedTempFile->GetPath(path); 1.1624 + if (NS_FAILED(rv)) 1.1625 + return E_FAIL; 1.1626 + 1.1627 + uint32_t allocLen = path.Length() + 2; 1.1628 + 1.1629 + // Two null characters are needed to terminate the file name list. 1.1630 + HGLOBAL hGlobalMemory = nullptr; 1.1631 + 1.1632 + aSTG.tymed = TYMED_HGLOBAL; 1.1633 + aSTG.pUnkForRelease = nullptr; 1.1634 + 1.1635 + hGlobalMemory = GlobalAlloc(GMEM_MOVEABLE, sizeof(DROPFILES) + allocLen * sizeof(char16_t)); 1.1636 + if (!hGlobalMemory) 1.1637 + return E_FAIL; 1.1638 + 1.1639 + DROPFILES* pDropFile = (DROPFILES*)GlobalLock(hGlobalMemory); 1.1640 + 1.1641 + // First, populate the drop file structure. 1.1642 + pDropFile->pFiles = sizeof(DROPFILES); // Offset to start of file name char array. 1.1643 + pDropFile->fNC = 0; 1.1644 + pDropFile->pt.x = 0; 1.1645 + pDropFile->pt.y = 0; 1.1646 + pDropFile->fWide = TRUE; 1.1647 + 1.1648 + // Copy the filename right after the DROPFILES structure. 1.1649 + char16_t* dest = (char16_t*)(((char*)pDropFile) + pDropFile->pFiles); 1.1650 + memcpy(dest, path.get(), (allocLen - 1) * sizeof(char16_t)); // Copies the null character in path as well. 1.1651 + 1.1652 + // Two null characters are needed at the end of the file name. 1.1653 + // Lookup the CF_HDROP shell clipboard format for more info. 1.1654 + // Add the second null character right after the first one. 1.1655 + dest[allocLen - 1] = L'\0'; 1.1656 + 1.1657 + GlobalUnlock(hGlobalMemory); 1.1658 + 1.1659 + aSTG.hGlobal = hGlobalMemory; 1.1660 + 1.1661 + return S_OK; 1.1662 +} 1.1663 + 1.1664 +//----------------------------------------------------- 1.1665 +HRESULT nsDataObj::GetMetafilePict(FORMATETC&, STGMEDIUM&) 1.1666 +{ 1.1667 + return E_NOTIMPL; 1.1668 +} 1.1669 + 1.1670 +//----------------------------------------------------- 1.1671 +HRESULT nsDataObj::SetBitmap(FORMATETC&, STGMEDIUM&) 1.1672 +{ 1.1673 + return E_NOTIMPL; 1.1674 +} 1.1675 + 1.1676 +//----------------------------------------------------- 1.1677 +HRESULT nsDataObj::SetDib(FORMATETC&, STGMEDIUM&) 1.1678 +{ 1.1679 + return E_FAIL; 1.1680 +} 1.1681 + 1.1682 +//----------------------------------------------------- 1.1683 +HRESULT nsDataObj::SetText (FORMATETC& aFE, STGMEDIUM& aSTG) 1.1684 +{ 1.1685 + return E_FAIL; 1.1686 +} 1.1687 + 1.1688 +//----------------------------------------------------- 1.1689 +HRESULT nsDataObj::SetMetafilePict(FORMATETC&, STGMEDIUM&) 1.1690 +{ 1.1691 + return E_FAIL; 1.1692 +} 1.1693 + 1.1694 + 1.1695 + 1.1696 +//----------------------------------------------------- 1.1697 +//----------------------------------------------------- 1.1698 +CLSID nsDataObj::GetClassID() const 1.1699 +{ 1.1700 + return CLSID_nsDataObj; 1.1701 +} 1.1702 + 1.1703 +//----------------------------------------------------- 1.1704 +// Registers the DataFlavor/FE pair. 1.1705 +//----------------------------------------------------- 1.1706 +void nsDataObj::AddDataFlavor(const char* aDataFlavor, LPFORMATETC aFE) 1.1707 +{ 1.1708 + // These two lists are the mapping to and from data flavors and FEs. 1.1709 + // Later, OLE will tell us it needs a certain type of FORMATETC (text, unicode, etc) 1.1710 + // unicode, etc), so we will look up the data flavor that corresponds to 1.1711 + // the FE and then ask the transferable for that type of data. 1.1712 + mDataFlavors.AppendElement(aDataFlavor); 1.1713 + m_enumFE->AddFormatEtc(aFE); 1.1714 +} 1.1715 + 1.1716 +//----------------------------------------------------- 1.1717 +// Sets the transferable object 1.1718 +//----------------------------------------------------- 1.1719 +void nsDataObj::SetTransferable(nsITransferable * aTransferable) 1.1720 +{ 1.1721 + NS_IF_RELEASE(mTransferable); 1.1722 + 1.1723 + mTransferable = aTransferable; 1.1724 + if (nullptr == mTransferable) { 1.1725 + return; 1.1726 + } 1.1727 + 1.1728 + NS_ADDREF(mTransferable); 1.1729 + 1.1730 + return; 1.1731 +} 1.1732 + 1.1733 + 1.1734 +// 1.1735 +// ExtractURL 1.1736 +// 1.1737 +// Roots around in the transferable for the appropriate flavor that indicates 1.1738 +// a url and pulls out the url portion of the data. Used mostly for creating 1.1739 +// internet shortcuts on the desktop. The url flavor is of the format: 1.1740 +// 1.1741 +// <url> <linefeed> <page title> 1.1742 +// 1.1743 +nsresult 1.1744 +nsDataObj :: ExtractShortcutURL ( nsString & outURL ) 1.1745 +{ 1.1746 + NS_ASSERTION ( mTransferable, "We don't have a good transferable" ); 1.1747 + nsresult rv = NS_ERROR_FAILURE; 1.1748 + 1.1749 + uint32_t len = 0; 1.1750 + nsCOMPtr<nsISupports> genericURL; 1.1751 + if ( NS_SUCCEEDED(mTransferable->GetTransferData(kURLMime, getter_AddRefs(genericURL), &len)) ) { 1.1752 + nsCOMPtr<nsISupportsString> urlObject ( do_QueryInterface(genericURL) ); 1.1753 + if ( urlObject ) { 1.1754 + nsAutoString url; 1.1755 + urlObject->GetData ( url ); 1.1756 + outURL = url; 1.1757 + 1.1758 + // find the first linefeed in the data, that's where the url ends. trunc the 1.1759 + // result string at that point. 1.1760 + int32_t lineIndex = outURL.FindChar ( '\n' ); 1.1761 + NS_ASSERTION ( lineIndex > 0, "Format for url flavor is <url> <linefeed> <page title>" ); 1.1762 + if ( lineIndex > 0 ) { 1.1763 + outURL.Truncate ( lineIndex ); 1.1764 + rv = NS_OK; 1.1765 + } 1.1766 + } 1.1767 + } else if ( NS_SUCCEEDED(mTransferable->GetTransferData(kURLDataMime, getter_AddRefs(genericURL), &len)) || 1.1768 + NS_SUCCEEDED(mTransferable->GetTransferData(kURLPrivateMime, getter_AddRefs(genericURL), &len)) ) { 1.1769 + nsCOMPtr<nsISupportsString> urlObject ( do_QueryInterface(genericURL) ); 1.1770 + if ( urlObject ) { 1.1771 + nsAutoString url; 1.1772 + urlObject->GetData ( url ); 1.1773 + outURL = url; 1.1774 + 1.1775 + rv = NS_OK; 1.1776 + } 1.1777 + 1.1778 + } // if found flavor 1.1779 + 1.1780 + return rv; 1.1781 + 1.1782 +} // ExtractShortcutURL 1.1783 + 1.1784 + 1.1785 +// 1.1786 +// ExtractShortcutTitle 1.1787 +// 1.1788 +// Roots around in the transferable for the appropriate flavor that indicates 1.1789 +// a url and pulls out the title portion of the data. Used mostly for creating 1.1790 +// internet shortcuts on the desktop. The url flavor is of the format: 1.1791 +// 1.1792 +// <url> <linefeed> <page title> 1.1793 +// 1.1794 +nsresult 1.1795 +nsDataObj :: ExtractShortcutTitle ( nsString & outTitle ) 1.1796 +{ 1.1797 + NS_ASSERTION ( mTransferable, "We'd don't have a good transferable" ); 1.1798 + nsresult rv = NS_ERROR_FAILURE; 1.1799 + 1.1800 + uint32_t len = 0; 1.1801 + nsCOMPtr<nsISupports> genericURL; 1.1802 + if ( NS_SUCCEEDED(mTransferable->GetTransferData(kURLMime, getter_AddRefs(genericURL), &len)) ) { 1.1803 + nsCOMPtr<nsISupportsString> urlObject ( do_QueryInterface(genericURL) ); 1.1804 + if ( urlObject ) { 1.1805 + nsAutoString url; 1.1806 + urlObject->GetData ( url ); 1.1807 + 1.1808 + // find the first linefeed in the data, that's where the url ends. we want 1.1809 + // everything after that linefeed. FindChar() returns -1 if we can't find 1.1810 + int32_t lineIndex = url.FindChar ( '\n' ); 1.1811 + NS_ASSERTION ( lineIndex != -1, "Format for url flavor is <url> <linefeed> <page title>" ); 1.1812 + if ( lineIndex != -1 ) { 1.1813 + url.Mid ( outTitle, lineIndex + 1, (len/2) - (lineIndex + 1) ); 1.1814 + rv = NS_OK; 1.1815 + } 1.1816 + } 1.1817 + } // if found flavor 1.1818 + 1.1819 + return rv; 1.1820 + 1.1821 +} // ExtractShortcutTitle 1.1822 + 1.1823 + 1.1824 +// 1.1825 +// BuildPlatformHTML 1.1826 +// 1.1827 +// Munge our HTML data to win32's CF_HTML spec. Basically, put the requisite 1.1828 +// header information on it. This will null terminate |outPlatformHTML|. See 1.1829 +// http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp 1.1830 +// for details. 1.1831 +// 1.1832 +// We assume that |inOurHTML| is already a fragment (ie, doesn't have <HTML> 1.1833 +// or <BODY> tags). We'll wrap the fragment with them to make other apps 1.1834 +// happy. 1.1835 +// 1.1836 +nsresult 1.1837 +nsDataObj :: BuildPlatformHTML ( const char* inOurHTML, char** outPlatformHTML ) 1.1838 +{ 1.1839 + *outPlatformHTML = nullptr; 1.1840 + 1.1841 + nsDependentCString inHTMLString(inOurHTML); 1.1842 + const char* const numPlaceholder = "00000000"; 1.1843 + const char* const startHTMLPrefix = "Version:0.9\r\nStartHTML:"; 1.1844 + const char* const endHTMLPrefix = "\r\nEndHTML:"; 1.1845 + const char* const startFragPrefix = "\r\nStartFragment:"; 1.1846 + const char* const endFragPrefix = "\r\nEndFragment:"; 1.1847 + const char* const startSourceURLPrefix = "\r\nSourceURL:"; 1.1848 + const char* const endFragTrailer = "\r\n"; 1.1849 + 1.1850 + // Do we already have mSourceURL from a drag? 1.1851 + if (mSourceURL.IsEmpty()) { 1.1852 + nsAutoString url; 1.1853 + ExtractShortcutURL(url); 1.1854 + 1.1855 + AppendUTF16toUTF8(url, mSourceURL); 1.1856 + } 1.1857 + 1.1858 + const int32_t kSourceURLLength = mSourceURL.Length(); 1.1859 + const int32_t kNumberLength = strlen(numPlaceholder); 1.1860 + 1.1861 + const int32_t kTotalHeaderLen = strlen(startHTMLPrefix) + 1.1862 + strlen(endHTMLPrefix) + 1.1863 + strlen(startFragPrefix) + 1.1864 + strlen(endFragPrefix) + 1.1865 + strlen(endFragTrailer) + 1.1866 + (kSourceURLLength > 0 ? strlen(startSourceURLPrefix) : 0) + 1.1867 + kSourceURLLength + 1.1868 + (4 * kNumberLength); 1.1869 + 1.1870 + NS_NAMED_LITERAL_CSTRING(htmlHeaderString, "<html><body>\r\n"); 1.1871 + 1.1872 + NS_NAMED_LITERAL_CSTRING(fragmentHeaderString, "<!--StartFragment-->"); 1.1873 + 1.1874 + nsDependentCString trailingString( 1.1875 + "<!--EndFragment-->\r\n" 1.1876 + "</body>\r\n" 1.1877 + "</html>"); 1.1878 + 1.1879 + // calculate the offsets 1.1880 + int32_t startHTMLOffset = kTotalHeaderLen; 1.1881 + int32_t startFragOffset = startHTMLOffset 1.1882 + + htmlHeaderString.Length() 1.1883 + + fragmentHeaderString.Length(); 1.1884 + 1.1885 + int32_t endFragOffset = startFragOffset 1.1886 + + inHTMLString.Length(); 1.1887 + 1.1888 + int32_t endHTMLOffset = endFragOffset 1.1889 + + trailingString.Length(); 1.1890 + 1.1891 + // now build the final version 1.1892 + nsCString clipboardString; 1.1893 + clipboardString.SetCapacity(endHTMLOffset); 1.1894 + 1.1895 + clipboardString.Append(startHTMLPrefix); 1.1896 + clipboardString.Append(nsPrintfCString("%08u", startHTMLOffset)); 1.1897 + 1.1898 + clipboardString.Append(endHTMLPrefix); 1.1899 + clipboardString.Append(nsPrintfCString("%08u", endHTMLOffset)); 1.1900 + 1.1901 + clipboardString.Append(startFragPrefix); 1.1902 + clipboardString.Append(nsPrintfCString("%08u", startFragOffset)); 1.1903 + 1.1904 + clipboardString.Append(endFragPrefix); 1.1905 + clipboardString.Append(nsPrintfCString("%08u", endFragOffset)); 1.1906 + 1.1907 + if (kSourceURLLength > 0) { 1.1908 + clipboardString.Append(startSourceURLPrefix); 1.1909 + clipboardString.Append(mSourceURL); 1.1910 + } 1.1911 + 1.1912 + clipboardString.Append(endFragTrailer); 1.1913 + 1.1914 + clipboardString.Append(htmlHeaderString); 1.1915 + clipboardString.Append(fragmentHeaderString); 1.1916 + clipboardString.Append(inHTMLString); 1.1917 + clipboardString.Append(trailingString); 1.1918 + 1.1919 + *outPlatformHTML = ToNewCString(clipboardString); 1.1920 + if (!*outPlatformHTML) 1.1921 + return NS_ERROR_OUT_OF_MEMORY; 1.1922 + 1.1923 + return NS_OK; 1.1924 +} 1.1925 + 1.1926 +HRESULT 1.1927 +nsDataObj :: GetUniformResourceLocator( FORMATETC& aFE, STGMEDIUM& aSTG, bool aIsUnicode ) 1.1928 +{ 1.1929 + HRESULT res = S_OK; 1.1930 + if (IsFlavourPresent(kURLMime)) { 1.1931 + if ( aIsUnicode ) 1.1932 + res = ExtractUniformResourceLocatorW( aFE, aSTG ); 1.1933 + else 1.1934 + res = ExtractUniformResourceLocatorA( aFE, aSTG ); 1.1935 + } 1.1936 + else 1.1937 + NS_WARNING ("Not yet implemented\n"); 1.1938 + return res; 1.1939 +} 1.1940 + 1.1941 +HRESULT 1.1942 +nsDataObj::ExtractUniformResourceLocatorA(FORMATETC& aFE, STGMEDIUM& aSTG ) 1.1943 +{ 1.1944 + HRESULT result = S_OK; 1.1945 + 1.1946 + nsAutoString url; 1.1947 + if (NS_FAILED(ExtractShortcutURL(url))) 1.1948 + return E_OUTOFMEMORY; 1.1949 + 1.1950 + NS_LossyConvertUTF16toASCII asciiUrl(url); 1.1951 + const int totalLen = asciiUrl.Length() + 1; 1.1952 + HGLOBAL hGlobalMemory = GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE, totalLen); 1.1953 + if (!hGlobalMemory) 1.1954 + return E_OUTOFMEMORY; 1.1955 + 1.1956 + char* contents = reinterpret_cast<char*>(GlobalLock(hGlobalMemory)); 1.1957 + if (!contents) { 1.1958 + GlobalFree(hGlobalMemory); 1.1959 + return E_OUTOFMEMORY; 1.1960 + } 1.1961 + 1.1962 + strcpy(contents, asciiUrl.get()); 1.1963 + GlobalUnlock(hGlobalMemory); 1.1964 + aSTG.hGlobal = hGlobalMemory; 1.1965 + aSTG.tymed = TYMED_HGLOBAL; 1.1966 + 1.1967 + return result; 1.1968 +} 1.1969 + 1.1970 +HRESULT 1.1971 +nsDataObj::ExtractUniformResourceLocatorW(FORMATETC& aFE, STGMEDIUM& aSTG ) 1.1972 +{ 1.1973 + HRESULT result = S_OK; 1.1974 + 1.1975 + nsAutoString url; 1.1976 + if (NS_FAILED(ExtractShortcutURL(url))) 1.1977 + return E_OUTOFMEMORY; 1.1978 + 1.1979 + const int totalLen = (url.Length() + 1) * sizeof(char16_t); 1.1980 + HGLOBAL hGlobalMemory = GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE, totalLen); 1.1981 + if (!hGlobalMemory) 1.1982 + return E_OUTOFMEMORY; 1.1983 + 1.1984 + wchar_t* contents = reinterpret_cast<wchar_t*>(GlobalLock(hGlobalMemory)); 1.1985 + if (!contents) { 1.1986 + GlobalFree(hGlobalMemory); 1.1987 + return E_OUTOFMEMORY; 1.1988 + } 1.1989 + 1.1990 + wcscpy(contents, url.get()); 1.1991 + GlobalUnlock(hGlobalMemory); 1.1992 + aSTG.hGlobal = hGlobalMemory; 1.1993 + aSTG.tymed = TYMED_HGLOBAL; 1.1994 + 1.1995 + return result; 1.1996 +} 1.1997 + 1.1998 + 1.1999 +// Gets the filename from the kFilePromiseURLMime flavour 1.2000 +HRESULT nsDataObj::GetDownloadDetails(nsIURI **aSourceURI, 1.2001 + nsAString &aFilename) 1.2002 +{ 1.2003 + *aSourceURI = nullptr; 1.2004 + 1.2005 + NS_ENSURE_TRUE(mTransferable, E_FAIL); 1.2006 + 1.2007 + // get the URI from the kFilePromiseURLMime flavor 1.2008 + nsCOMPtr<nsISupports> urlPrimitive; 1.2009 + uint32_t dataSize = 0; 1.2010 + mTransferable->GetTransferData(kFilePromiseURLMime, getter_AddRefs(urlPrimitive), &dataSize); 1.2011 + nsCOMPtr<nsISupportsString> srcUrlPrimitive = do_QueryInterface(urlPrimitive); 1.2012 + NS_ENSURE_TRUE(srcUrlPrimitive, E_FAIL); 1.2013 + 1.2014 + nsAutoString srcUri; 1.2015 + srcUrlPrimitive->GetData(srcUri); 1.2016 + if (srcUri.IsEmpty()) 1.2017 + return E_FAIL; 1.2018 + nsCOMPtr<nsIURI> sourceURI; 1.2019 + NS_NewURI(getter_AddRefs(sourceURI), srcUri); 1.2020 + 1.2021 + nsAutoString srcFileName; 1.2022 + nsCOMPtr<nsISupports> fileNamePrimitive; 1.2023 + mTransferable->GetTransferData(kFilePromiseDestFilename, getter_AddRefs(fileNamePrimitive), &dataSize); 1.2024 + nsCOMPtr<nsISupportsString> srcFileNamePrimitive = do_QueryInterface(fileNamePrimitive); 1.2025 + if (srcFileNamePrimitive) { 1.2026 + srcFileNamePrimitive->GetData(srcFileName); 1.2027 + } else { 1.2028 + nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(sourceURI); 1.2029 + if (!sourceURL) 1.2030 + return E_FAIL; 1.2031 + 1.2032 + nsAutoCString urlFileName; 1.2033 + sourceURL->GetFileName(urlFileName); 1.2034 + NS_UnescapeURL(urlFileName); 1.2035 + CopyUTF8toUTF16(urlFileName, srcFileName); 1.2036 + } 1.2037 + if (srcFileName.IsEmpty()) 1.2038 + return E_FAIL; 1.2039 + 1.2040 + // make the name safe for the filesystem 1.2041 + MangleTextToValidFilename(srcFileName); 1.2042 + 1.2043 + sourceURI.swap(*aSourceURI); 1.2044 + aFilename = srcFileName; 1.2045 + return S_OK; 1.2046 +} 1.2047 + 1.2048 +HRESULT nsDataObj::GetFileDescriptor_IStreamA(FORMATETC& aFE, STGMEDIUM& aSTG) 1.2049 +{ 1.2050 + HGLOBAL fileGroupDescHandle = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE,sizeof(FILEGROUPDESCRIPTORW)); 1.2051 + NS_ENSURE_TRUE(fileGroupDescHandle, E_OUTOFMEMORY); 1.2052 + 1.2053 + LPFILEGROUPDESCRIPTORA fileGroupDescA = reinterpret_cast<LPFILEGROUPDESCRIPTORA>(GlobalLock(fileGroupDescHandle)); 1.2054 + if (!fileGroupDescA) { 1.2055 + ::GlobalFree(fileGroupDescHandle); 1.2056 + return E_OUTOFMEMORY; 1.2057 + } 1.2058 + 1.2059 + nsAutoString wideFileName; 1.2060 + HRESULT res; 1.2061 + nsCOMPtr<nsIURI> sourceURI; 1.2062 + res = GetDownloadDetails(getter_AddRefs(sourceURI), wideFileName); 1.2063 + if (FAILED(res)) 1.2064 + { 1.2065 + ::GlobalFree(fileGroupDescHandle); 1.2066 + return res; 1.2067 + } 1.2068 + 1.2069 + nsAutoCString nativeFileName; 1.2070 + NS_UTF16ToCString(wideFileName, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM, nativeFileName); 1.2071 + 1.2072 + strncpy(fileGroupDescA->fgd[0].cFileName, nativeFileName.get(), NS_MAX_FILEDESCRIPTOR - 1); 1.2073 + fileGroupDescA->fgd[0].cFileName[NS_MAX_FILEDESCRIPTOR - 1] = '\0'; 1.2074 + 1.2075 + // one file in the file block 1.2076 + fileGroupDescA->cItems = 1; 1.2077 + fileGroupDescA->fgd[0].dwFlags = FD_PROGRESSUI; 1.2078 + 1.2079 + GlobalUnlock( fileGroupDescHandle ); 1.2080 + aSTG.hGlobal = fileGroupDescHandle; 1.2081 + aSTG.tymed = TYMED_HGLOBAL; 1.2082 + 1.2083 + return S_OK; 1.2084 +} 1.2085 + 1.2086 +HRESULT nsDataObj::GetFileDescriptor_IStreamW(FORMATETC& aFE, STGMEDIUM& aSTG) 1.2087 +{ 1.2088 + HGLOBAL fileGroupDescHandle = ::GlobalAlloc(GMEM_ZEROINIT|GMEM_SHARE,sizeof(FILEGROUPDESCRIPTORW)); 1.2089 + NS_ENSURE_TRUE(fileGroupDescHandle, E_OUTOFMEMORY); 1.2090 + 1.2091 + LPFILEGROUPDESCRIPTORW fileGroupDescW = reinterpret_cast<LPFILEGROUPDESCRIPTORW>(GlobalLock(fileGroupDescHandle)); 1.2092 + if (!fileGroupDescW) { 1.2093 + ::GlobalFree(fileGroupDescHandle); 1.2094 + return E_OUTOFMEMORY; 1.2095 + } 1.2096 + 1.2097 + nsAutoString wideFileName; 1.2098 + HRESULT res; 1.2099 + nsCOMPtr<nsIURI> sourceURI; 1.2100 + res = GetDownloadDetails(getter_AddRefs(sourceURI), 1.2101 + wideFileName); 1.2102 + if (FAILED(res)) 1.2103 + { 1.2104 + ::GlobalFree(fileGroupDescHandle); 1.2105 + return res; 1.2106 + } 1.2107 + 1.2108 + wcsncpy(fileGroupDescW->fgd[0].cFileName, wideFileName.get(), NS_MAX_FILEDESCRIPTOR - 1); 1.2109 + fileGroupDescW->fgd[0].cFileName[NS_MAX_FILEDESCRIPTOR - 1] = '\0'; 1.2110 + // one file in the file block 1.2111 + fileGroupDescW->cItems = 1; 1.2112 + fileGroupDescW->fgd[0].dwFlags = FD_PROGRESSUI; 1.2113 + 1.2114 + GlobalUnlock(fileGroupDescHandle); 1.2115 + aSTG.hGlobal = fileGroupDescHandle; 1.2116 + aSTG.tymed = TYMED_HGLOBAL; 1.2117 + 1.2118 + return S_OK; 1.2119 +} 1.2120 + 1.2121 +HRESULT nsDataObj::GetFileContents_IStream(FORMATETC& aFE, STGMEDIUM& aSTG) 1.2122 +{ 1.2123 + IStream *pStream = nullptr; 1.2124 + 1.2125 + nsDataObj::CreateStream(&pStream); 1.2126 + NS_ENSURE_TRUE(pStream, E_FAIL); 1.2127 + 1.2128 + aSTG.tymed = TYMED_ISTREAM; 1.2129 + aSTG.pstm = pStream; 1.2130 + aSTG.pUnkForRelease = nullptr; 1.2131 + 1.2132 + return S_OK; 1.2133 +} 1.2134 + 1.2135 +void nsDataObj::RemoveTempFile(nsITimer* aTimer, void* aClosure) 1.2136 +{ 1.2137 + nsDataObj *timedDataObj = static_cast<nsDataObj *>(aClosure); 1.2138 + if (timedDataObj->mCachedTempFile) { 1.2139 + timedDataObj->mCachedTempFile->Remove(false); 1.2140 + timedDataObj->mCachedTempFile = nullptr; 1.2141 + } 1.2142 + timedDataObj->Release(); 1.2143 +}