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 #include "mozilla/ArrayUtils.h"
11 #include "nsDataObj.h"
12 #include "nsClipboard.h"
13 #include "nsReadableUtils.h"
14 #include "nsITransferable.h"
15 #include "nsISupportsPrimitives.h"
17 #include "nsPrimitiveHelpers.h"
18 #include "nsXPIDLString.h"
19 #include "nsImageClipboard.h"
21 #include "nsPrintfCString.h"
22 #include "nsIStringBundle.h"
25 #include "nsNetUtil.h"
26 #include "nsXPCOMStrings.h"
28 #include "nsDirectoryServiceDefs.h"
30 #include "nsThreadUtils.h"
31 #include "mozilla/Preferences.h"
32 #include "nsIContentPolicy.h"
33 #include "nsContentUtils.h"
37 #include "mozilla/LazyIdleThread.h"
38 #include "mozilla/WindowsVersion.h"
42 using namespace mozilla
;
43 using namespace mozilla::widget
;
45 #define DEFAULT_THREAD_TIMEOUT_MS 30000
47 NS_IMPL_ISUPPORTS(nsDataObj::CStream
, nsIStreamListener
)
49 //-----------------------------------------------------------------------------
50 // CStream implementation
51 nsDataObj::CStream::CStream() :
57 //-----------------------------------------------------------------------------
58 nsDataObj::CStream::~CStream()
62 //-----------------------------------------------------------------------------
63 // helper - initializes the stream
64 nsresult
nsDataObj::CStream::Init(nsIURI
*pSourceURI
,
65 nsINode
* aRequestingNode
)
67 // we can not create a channel without a requestingNode
68 if (!aRequestingNode
) {
69 return NS_ERROR_FAILURE
;
72 rv
= NS_NewChannel(getter_AddRefs(mChannel
),
75 nsILoadInfo::SEC_NORMAL
,
76 nsIContentPolicy::TYPE_OTHER
,
78 nullptr, // aCallbacks
79 nsIRequest::LOAD_FROM_CACHE
);
81 NS_ENSURE_SUCCESS(rv
, rv
);
82 rv
= mChannel
->AsyncOpen(this, nullptr);
83 NS_ENSURE_SUCCESS(rv
, rv
);
87 //-----------------------------------------------------------------------------
88 // IUnknown's QueryInterface, nsISupport's AddRef and Release are shared by
89 // IUnknown and nsIStreamListener.
90 STDMETHODIMP
nsDataObj::CStream::QueryInterface(REFIID refiid
, void** ppvResult
)
93 if (IID_IUnknown
== refiid
||
94 refiid
== IID_IStream
)
100 if (nullptr != *ppvResult
)
102 ((LPUNKNOWN
)*ppvResult
)->AddRef();
106 return E_NOINTERFACE
;
109 // nsIStreamListener implementation
111 nsDataObj::CStream::OnDataAvailable(nsIRequest
*aRequest
,
112 nsISupports
*aContext
,
113 nsIInputStream
*aInputStream
,
114 uint64_t aOffset
, // offset within the stream
115 uint32_t aCount
) // bytes available on this call
117 // Extend the write buffer for the incoming data.
118 uint8_t* buffer
= mChannelData
.AppendElements(aCount
);
119 if (buffer
== nullptr)
120 return NS_ERROR_OUT_OF_MEMORY
;
121 NS_ASSERTION((mChannelData
.Length() == (aOffset
+ aCount
)),
122 "stream length mismatch w/write buffer");
124 // Read() may not return aCount on a single call, so loop until we've
125 // accumulated all the data OnDataAvailable has promised.
127 uint32_t odaBytesReadTotal
= 0;
129 uint32_t bytesReadByCall
= 0;
130 rv
= aInputStream
->Read((char*)(buffer
+ odaBytesReadTotal
),
131 aCount
, &bytesReadByCall
);
132 odaBytesReadTotal
+= bytesReadByCall
;
133 } while (aCount
< odaBytesReadTotal
&& NS_SUCCEEDED(rv
));
137 NS_IMETHODIMP
nsDataObj::CStream::OnStartRequest(nsIRequest
*aRequest
,
138 nsISupports
*aContext
)
140 mChannelResult
= NS_OK
;
144 NS_IMETHODIMP
nsDataObj::CStream::OnStopRequest(nsIRequest
*aRequest
,
145 nsISupports
*aContext
,
146 nsresult aStatusCode
)
149 mChannelResult
= aStatusCode
;
153 // Pumps thread messages while waiting for the async listener operation to
154 // complete. Failing this call will fail the stream incall from Windows
155 // and cancel the operation.
156 nsresult
nsDataObj::CStream::WaitForCompletion()
158 // We are guaranteed OnStopRequest will get called, so this should be ok.
159 while (!mChannelRead
) {
161 NS_ProcessNextEvent(nullptr, true);
164 if (!mChannelData
.Length())
165 mChannelResult
= NS_ERROR_FAILURE
;
167 return mChannelResult
;
170 //-----------------------------------------------------------------------------
172 STDMETHODIMP
nsDataObj::CStream::Clone(IStream
** ppStream
)
177 //-----------------------------------------------------------------------------
178 STDMETHODIMP
nsDataObj::CStream::Commit(DWORD dwFrags
)
183 //-----------------------------------------------------------------------------
184 STDMETHODIMP
nsDataObj::CStream::CopyTo(IStream
* pDestStream
,
185 ULARGE_INTEGER nBytesToCopy
,
186 ULARGE_INTEGER
* nBytesRead
,
187 ULARGE_INTEGER
* nBytesWritten
)
192 //-----------------------------------------------------------------------------
193 STDMETHODIMP
nsDataObj::CStream::LockRegion(ULARGE_INTEGER nStart
,
194 ULARGE_INTEGER nBytes
,
200 //-----------------------------------------------------------------------------
201 STDMETHODIMP
nsDataObj::CStream::Read(void* pvBuffer
,
205 // Wait for the write into our buffer to complete via the stream listener.
206 // We can't respond to this by saying "call us back later".
207 if (NS_FAILED(WaitForCompletion()))
210 // Bytes left for Windows to read out of our buffer
211 ULONG bytesLeft
= mChannelData
.Length() - mStreamRead
;
212 // Let Windows know what we will hand back, usually this is the entire buffer
213 *nBytesRead
= std::min(bytesLeft
, nBytesToRead
);
214 // Copy the buffer data over
215 memcpy(pvBuffer
, ((char*)mChannelData
.Elements() + mStreamRead
), *nBytesRead
);
216 // Update our bytes read tracking
217 mStreamRead
+= *nBytesRead
;
221 //-----------------------------------------------------------------------------
222 STDMETHODIMP
nsDataObj::CStream::Revert(void)
227 //-----------------------------------------------------------------------------
228 STDMETHODIMP
nsDataObj::CStream::Seek(LARGE_INTEGER nMove
,
230 ULARGE_INTEGER
* nNewPos
)
232 if (nNewPos
== nullptr)
233 return STG_E_INVALIDPOINTER
;
235 if (nMove
.LowPart
== 0 && nMove
.HighPart
== 0 &&
236 (dwOrigin
== STREAM_SEEK_SET
|| dwOrigin
== STREAM_SEEK_CUR
)) {
237 nNewPos
->LowPart
= 0;
238 nNewPos
->HighPart
= 0;
245 //-----------------------------------------------------------------------------
246 STDMETHODIMP
nsDataObj::CStream::SetSize(ULARGE_INTEGER nNewSize
)
251 //-----------------------------------------------------------------------------
252 STDMETHODIMP
nsDataObj::CStream::Stat(STATSTG
* statstg
, DWORD dwFlags
)
254 if (statstg
== nullptr)
255 return STG_E_INVALIDPOINTER
;
257 if (!mChannel
|| NS_FAILED(WaitForCompletion()))
260 memset((void*)statstg
, 0, sizeof(STATSTG
));
262 if (dwFlags
!= STATFLAG_NONAME
)
264 nsCOMPtr
<nsIURI
> sourceURI
;
265 if (NS_FAILED(mChannel
->GetURI(getter_AddRefs(sourceURI
)))) {
269 nsAutoCString strFileName
;
270 nsCOMPtr
<nsIURL
> sourceURL
= do_QueryInterface(sourceURI
);
271 sourceURL
->GetFileName(strFileName
);
273 if (strFileName
.IsEmpty())
276 NS_UnescapeURL(strFileName
);
277 NS_ConvertUTF8toUTF16
wideFileName(strFileName
);
279 uint32_t nMaxNameLength
= (wideFileName
.Length()*2) + 2;
280 void * retBuf
= CoTaskMemAlloc(nMaxNameLength
); // freed by caller
282 return STG_E_INSUFFICIENTMEMORY
;
284 ZeroMemory(retBuf
, nMaxNameLength
);
285 memcpy(retBuf
, wideFileName
.get(), wideFileName
.Length()*2);
286 statstg
->pwcsName
= (LPOLESTR
)retBuf
;
291 statstg
->type
= STGTY_STREAM
;
294 SystemTimeToFileTime((const SYSTEMTIME
*)&st
, (LPFILETIME
)&statstg
->mtime
);
295 statstg
->ctime
= statstg
->atime
= statstg
->mtime
;
297 statstg
->cbSize
.LowPart
= (DWORD
)mChannelData
.Length();
298 statstg
->grfMode
= STGM_READ
;
299 statstg
->grfLocksSupported
= LOCK_ONLYONCE
;
300 statstg
->clsid
= CLSID_NULL
;
305 //-----------------------------------------------------------------------------
306 STDMETHODIMP
nsDataObj::CStream::UnlockRegion(ULARGE_INTEGER nStart
,
307 ULARGE_INTEGER nBytes
,
313 //-----------------------------------------------------------------------------
314 STDMETHODIMP
nsDataObj::CStream::Write(const void* pvBuffer
,
321 //-----------------------------------------------------------------------------
322 HRESULT
nsDataObj::CreateStream(IStream
**outStream
)
324 NS_ENSURE_TRUE(outStream
, E_INVALIDARG
);
326 nsresult rv
= NS_ERROR_FAILURE
;
327 nsAutoString wideFileName
;
328 nsCOMPtr
<nsIURI
> sourceURI
;
331 res
= GetDownloadDetails(getter_AddRefs(sourceURI
),
336 nsDataObj::CStream
*pStream
= new nsDataObj::CStream();
337 NS_ENSURE_TRUE(pStream
, E_OUTOFMEMORY
);
341 // query the requestingNode from the transferable and add it to the new channel
342 nsCOMPtr
<nsIDOMNode
> requestingDomNode
;
343 mTransferable
->GetRequestingNode(getter_AddRefs(requestingDomNode
));
344 nsCOMPtr
<nsINode
> requestingNode
= do_QueryInterface(requestingDomNode
);
345 MOZ_ASSERT(requestingNode
, "can not create channel without a node");
347 rv
= pStream
->Init(sourceURI
, requestingNode
);
353 *outStream
= pStream
;
358 static GUID CLSID_nsDataObj
=
359 { 0x1bba7640, 0xdf52, 0x11cf, { 0x82, 0x7b, 0, 0xa0, 0x24, 0x3a, 0xe5, 0x05 } };
362 * deliberately not using MAX_PATH. This is because on platforms < XP
363 * a file created with a long filename may be mishandled by the shell
364 * resulting in it not being able to be deleted or moved.
365 * See bug 250392 for more details.
367 #define NS_MAX_FILEDESCRIPTOR 128 + 1
373 //-----------------------------------------------------
375 //-----------------------------------------------------
376 nsDataObj::nsDataObj(nsIURI
* uri
)
377 : m_cRef(0), mTransferable(nullptr),
378 mIsAsyncMode(FALSE
), mIsInOperation(FALSE
)
380 mIOThread
= new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS
,
381 NS_LITERAL_CSTRING("nsDataObj"),
382 LazyIdleThread::ManualShutdown
);
383 m_enumFE
= new CEnumFormatEtc();
387 // A URI was obtained, so pass this through to the DataObject
388 // so it can create a SourceURL for CF_HTML flavour
389 uri
->GetSpec(mSourceURL
);
392 //-----------------------------------------------------
394 //-----------------------------------------------------
395 nsDataObj::~nsDataObj()
397 NS_IF_RELEASE(mTransferable
);
399 mDataFlavors
.Clear();
403 // Free arbitrary system formats
404 for (uint32_t idx
= 0; idx
< mDataEntryList
.Length(); idx
++) {
405 CoTaskMemFree(mDataEntryList
[idx
]->fe
.ptd
);
406 ReleaseStgMedium(&mDataEntryList
[idx
]->stgm
);
407 CoTaskMemFree(mDataEntryList
[idx
]);
412 //-----------------------------------------------------
413 // IUnknown interface methods - see inknown.h for documentation
414 //-----------------------------------------------------
415 STDMETHODIMP
nsDataObj::QueryInterface(REFIID riid
, void** ppv
)
419 if ( (IID_IUnknown
== riid
) || (IID_IDataObject
== riid
) ) {
423 } else if (IID_IAsyncOperation
== riid
) {
424 *ppv
= static_cast<IAsyncOperation
*>(this);
429 return E_NOINTERFACE
;
432 //-----------------------------------------------------
433 STDMETHODIMP_(ULONG
) nsDataObj::AddRef()
436 NS_LOG_ADDREF(this, m_cRef
, "nsDataObj", sizeof(*this));
441 //-----------------------------------------------------
442 STDMETHODIMP_(ULONG
) nsDataObj::Release()
446 NS_LOG_RELEASE(this, m_cRef
, "nsDataObj");
450 // We have released our last ref on this object and need to delete the
451 // temp file. External app acting as drop target may still need to open the
452 // temp file. Addref a timer so it can delay deleting file and destroying
453 // this object. Delete file anyway and destroy this obj if there's a problem.
454 if (mCachedTempFile
) {
456 mTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
, &rv
);
457 if (NS_SUCCEEDED(rv
)) {
458 mTimer
->InitWithFuncCallback(nsDataObj::RemoveTempFile
, this,
459 500, nsITimer::TYPE_ONE_SHOT
);
462 mCachedTempFile
->Remove(false);
463 mCachedTempFile
= nullptr;
471 //-----------------------------------------------------
472 BOOL
nsDataObj::FormatsMatch(const FORMATETC
& source
, const FORMATETC
& target
) const
474 if ((source
.cfFormat
== target
.cfFormat
) &&
475 (source
.dwAspect
& target
.dwAspect
) &&
476 (source
.tymed
& target
.tymed
)) {
483 //-----------------------------------------------------
484 // IDataObject methods
485 //-----------------------------------------------------
486 STDMETHODIMP
nsDataObj::GetData(LPFORMATETC aFormat
, LPSTGMEDIUM pSTM
)
489 return DV_E_FORMATETC
;
493 static CLIPFORMAT fileDescriptorFlavorA
= ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORA
);
494 static CLIPFORMAT fileDescriptorFlavorW
= ::RegisterClipboardFormat( CFSTR_FILEDESCRIPTORW
);
495 static CLIPFORMAT uniformResourceLocatorA
= ::RegisterClipboardFormat( CFSTR_INETURLA
);
496 static CLIPFORMAT uniformResourceLocatorW
= ::RegisterClipboardFormat( CFSTR_INETURLW
);
497 static CLIPFORMAT fileFlavor
= ::RegisterClipboardFormat( CFSTR_FILECONTENTS
);
498 static CLIPFORMAT PreferredDropEffect
= ::RegisterClipboardFormat( CFSTR_PREFERREDDROPEFFECT
);
500 // Arbitrary system formats are used for image feedback during drag
501 // and drop. We are responsible for storing these internally during
504 if (LookupArbitraryFormat(aFormat
, &pde
, FALSE
)) {
505 return CopyMediumData(pSTM
, &pde
->stgm
, aFormat
, FALSE
)
506 ? S_OK
: E_UNEXPECTED
;
509 // Firefox internal formats
513 while (NOERROR
== m_enumFE
->Next(1, &fe
, &count
)
514 && dfInx
< mDataFlavors
.Length()) {
515 nsCString
& df
= mDataFlavors
.ElementAt(dfInx
);
516 if (FormatsMatch(fe
, *aFormat
)) {
517 pSTM
->pUnkForRelease
= nullptr; // caller is responsible for deleting this data
518 CLIPFORMAT format
= aFormat
->cfFormat
;
521 // Someone is asking for plain or unicode text
524 return GetText(df
, *aFormat
, *pSTM
);
526 // Some 3rd party apps that receive drag and drop files from the browser
527 // window require support for this.
529 return GetFile(*aFormat
, *pSTM
);
531 // Someone is asking for an image
534 return GetDib(df
, *aFormat
, *pSTM
);
537 if ( format
== fileDescriptorFlavorA
)
538 return GetFileDescriptor ( *aFormat
, *pSTM
, false );
539 if ( format
== fileDescriptorFlavorW
)
540 return GetFileDescriptor ( *aFormat
, *pSTM
, true);
541 if ( format
== uniformResourceLocatorA
)
542 return GetUniformResourceLocator( *aFormat
, *pSTM
, false);
543 if ( format
== uniformResourceLocatorW
)
544 return GetUniformResourceLocator( *aFormat
, *pSTM
, true);
545 if ( format
== fileFlavor
)
546 return GetFileContents ( *aFormat
, *pSTM
);
547 if ( format
== PreferredDropEffect
)
548 return GetPreferredDropEffect( *aFormat
, *pSTM
);
549 //PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
550 // ("***** nsDataObj::GetData - Unknown format %u\n", format));
551 return GetText(df
, *aFormat
, *pSTM
);
557 return DATA_E_FORMATETC
;
560 //-----------------------------------------------------
561 STDMETHODIMP
nsDataObj::GetDataHere(LPFORMATETC pFE
, LPSTGMEDIUM pSTM
)
567 //-----------------------------------------------------
568 // Other objects querying to see if we support a
570 //-----------------------------------------------------
571 STDMETHODIMP
nsDataObj::QueryGetData(LPFORMATETC pFE
)
573 // Arbitrary system formats are used for image feedback during drag
574 // and drop. We are responsible for storing these internally during
577 if (LookupArbitraryFormat(pFE
, &pde
, FALSE
))
580 // Firefox internal formats
584 while (NOERROR
== m_enumFE
->Next(1, &fe
, &count
)) {
585 if (fe
.cfFormat
== pFE
->cfFormat
) {
592 //-----------------------------------------------------
593 STDMETHODIMP
nsDataObj::GetCanonicalFormatEtc
594 (LPFORMATETC pFEIn
, LPFORMATETC pFEOut
)
599 //-----------------------------------------------------
600 STDMETHODIMP
nsDataObj::SetData(LPFORMATETC aFormat
, LPSTGMEDIUM aMedium
, BOOL shouldRel
)
602 // Arbitrary system formats are used for image feedback during drag
603 // and drop. We are responsible for storing these internally during
606 if (LookupArbitraryFormat(aFormat
, &pde
, TRUE
)) {
607 // Release the old data the lookup handed us for this format. This
608 // may have been set in CopyMediumData when we originally stored the
610 if (pde
->stgm
.tymed
) {
611 ReleaseStgMedium(&pde
->stgm
);
612 memset(&pde
->stgm
, 0, sizeof(STGMEDIUM
));
617 // If shouldRel is TRUE, the data object called owns the storage medium
618 // after the call returns. Store the incoming data in our data array for
619 // release when we are destroyed. This is the common case with arbitrary
620 // data from explorer.
621 pde
->stgm
= *aMedium
;
623 // Copy the incoming data into our data array. (AFAICT, this never gets
624 // called with arbitrary formats for drag images.)
625 result
= CopyMediumData(&pde
->stgm
, aMedium
, aFormat
, TRUE
);
627 pde
->fe
.tymed
= pde
->stgm
.tymed
;
629 return result
? S_OK
: DV_E_TYMED
;
633 ReleaseStgMedium(aMedium
);
639 nsDataObj::LookupArbitraryFormat(FORMATETC
*aFormat
, LPDATAENTRY
*aDataEntry
, BOOL aAddorUpdate
)
641 *aDataEntry
= nullptr;
643 if (aFormat
->ptd
!= nullptr)
646 // See if it's already in our list. If so return the data entry.
647 for (uint32_t idx
= 0; idx
< mDataEntryList
.Length(); idx
++) {
648 if (mDataEntryList
[idx
]->fe
.cfFormat
== aFormat
->cfFormat
&&
649 mDataEntryList
[idx
]->fe
.dwAspect
== aFormat
->dwAspect
&&
650 mDataEntryList
[idx
]->fe
.lindex
== aFormat
->lindex
) {
651 if (aAddorUpdate
|| (mDataEntryList
[idx
]->fe
.tymed
& aFormat
->tymed
)) {
652 // If the caller requests we update, or if the
653 // medium type matches, return the entry.
654 *aDataEntry
= mDataEntryList
[idx
];
657 // Medium does not match, not found.
666 // Add another entry to mDataEntryList
667 LPDATAENTRY dataEntry
= (LPDATAENTRY
)CoTaskMemAlloc(sizeof(DATAENTRY
));
671 dataEntry
->fe
= *aFormat
;
672 *aDataEntry
= dataEntry
;
673 memset(&dataEntry
->stgm
, 0, sizeof(STGMEDIUM
));
675 // Add this to our IEnumFORMATETC impl. so we can return it when
677 m_enumFE
->AddFormatEtc(aFormat
);
679 // Store a copy internally in the arbitrary formats array.
680 mDataEntryList
.AppendElement(dataEntry
);
686 nsDataObj::CopyMediumData(STGMEDIUM
*aMediumDst
, STGMEDIUM
*aMediumSrc
, LPFORMATETC aFormat
, BOOL aSetData
)
688 STGMEDIUM stgmOut
= *aMediumSrc
;
690 switch (stgmOut
.tymed
) {
692 stgmOut
.pstm
->AddRef();
695 stgmOut
.pstg
->AddRef();
698 if (!aMediumSrc
->pUnkForRelease
) {
700 if (aMediumSrc
->tymed
!= TYMED_HGLOBAL
)
702 stgmOut
.hGlobal
= OleDuplicateData(aMediumSrc
->hGlobal
, aFormat
->cfFormat
, 0);
703 if (!stgmOut
.hGlobal
)
706 // We are returning this data from LookupArbitraryFormat, indicate to the
707 // shell we hold it and will free it.
708 stgmOut
.pUnkForRelease
= static_cast<IDataObject
*>(this);
716 if (stgmOut
.pUnkForRelease
)
717 stgmOut
.pUnkForRelease
->AddRef();
719 *aMediumDst
= stgmOut
;
724 //-----------------------------------------------------
725 STDMETHODIMP
nsDataObj::EnumFormatEtc(DWORD dwDir
, LPENUMFORMATETC
*ppEnum
)
729 m_enumFE
->Clone(ppEnum
);
737 if (nullptr == *ppEnum
)
741 // Clone already AddRefed the result so don't addref it again.
745 //-----------------------------------------------------
746 STDMETHODIMP
nsDataObj::DAdvise(LPFORMATETC pFE
, DWORD dwFlags
,
747 LPADVISESINK pIAdviseSink
, DWORD
* pdwConn
)
749 return OLE_E_ADVISENOTSUPPORTED
;
753 //-----------------------------------------------------
754 STDMETHODIMP
nsDataObj::DUnadvise(DWORD dwConn
)
756 return OLE_E_ADVISENOTSUPPORTED
;
759 //-----------------------------------------------------
760 STDMETHODIMP
nsDataObj::EnumDAdvise(LPENUMSTATDATA
*ppEnum
)
762 return OLE_E_ADVISENOTSUPPORTED
;
765 // IAsyncOperation methods
766 STDMETHODIMP
nsDataObj::EndOperation(HRESULT hResult
,
767 IBindCtx
*pbcReserved
,
770 mIsInOperation
= FALSE
;
774 STDMETHODIMP
nsDataObj::GetAsyncMode(BOOL
*pfIsOpAsync
)
776 *pfIsOpAsync
= mIsAsyncMode
;
781 STDMETHODIMP
nsDataObj::InOperation(BOOL
*pfInAsyncOp
)
783 *pfInAsyncOp
= mIsInOperation
;
788 STDMETHODIMP
nsDataObj::SetAsyncMode(BOOL fDoOpAsync
)
790 mIsAsyncMode
= fDoOpAsync
;
794 STDMETHODIMP
nsDataObj::StartOperation(IBindCtx
*pbcReserved
)
796 mIsInOperation
= TRUE
;
800 //-----------------------------------------------------
801 // GetData and SetData helper functions
802 //-----------------------------------------------------
803 HRESULT
nsDataObj::AddSetFormat(FORMATETC
& aFE
)
808 //-----------------------------------------------------
809 HRESULT
nsDataObj::AddGetFormat(FORMATETC
& aFE
)
817 // Someone is asking for a bitmap. The data in the transferable will be a straight
818 // imgIContainer, so just QI it.
821 nsDataObj::GetDib(const nsACString
& inFlavor
,
825 ULONG result
= E_FAIL
;
827 nsCOMPtr
<nsISupports
> genericDataWrapper
;
828 mTransferable
->GetTransferData(PromiseFlatCString(inFlavor
).get(), getter_AddRefs(genericDataWrapper
), &len
);
829 nsCOMPtr
<imgIContainer
> image ( do_QueryInterface(genericDataWrapper
) );
831 // Check if the image was put in an nsISupportsInterfacePointer wrapper.
832 // This might not be necessary any more, but could be useful for backwards
834 nsCOMPtr
<nsISupportsInterfacePointer
> ptr(do_QueryInterface(genericDataWrapper
));
836 nsCOMPtr
<nsISupports
> supports
;
837 ptr
->GetData(getter_AddRefs(supports
));
838 image
= do_QueryInterface(supports
);
843 // use the |nsImageToClipboard| helper class to build up a bitmap. We now own
844 // the bits, and pass them back to the OS in |aSTG|.
845 nsImageToClipboard
converter(image
, aFormat
.cfFormat
== CF_DIBV5
);
846 HANDLE bits
= nullptr;
847 nsresult rv
= converter
.GetPicture ( &bits
);
848 if ( NS_SUCCEEDED(rv
) && bits
) {
850 aSTG
.tymed
= TYMED_HGLOBAL
;
853 } // if we have an image
855 NS_WARNING ( "Definitely not an image on clipboard" );
866 nsDataObj :: GetFileDescriptor ( FORMATETC
& aFE
, STGMEDIUM
& aSTG
, bool aIsUnicode
)
870 // How we handle this depends on if we're dealing with an internet
871 // shortcut, since those are done under the covers.
872 if (IsFlavourPresent(kFilePromiseMime
) ||
873 IsFlavourPresent(kFileMime
))
876 return GetFileDescriptor_IStreamW(aFE
, aSTG
);
878 return GetFileDescriptor_IStreamA(aFE
, aSTG
);
880 else if (IsFlavourPresent(kURLMime
))
883 res
= GetFileDescriptorInternetShortcutW ( aFE
, aSTG
);
885 res
= GetFileDescriptorInternetShortcutA ( aFE
, aSTG
);
888 NS_WARNING ( "Not yet implemented\n" );
891 } // GetFileDescriptor
896 nsDataObj :: GetFileContents ( FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
900 // How we handle this depends on if we're dealing with an internet
901 // shortcut, since those are done under the covers.
902 if (IsFlavourPresent(kFilePromiseMime
) ||
903 IsFlavourPresent(kFileMime
))
904 return GetFileContents_IStream(aFE
, aSTG
);
905 else if (IsFlavourPresent(kURLMime
))
906 return GetFileContentsInternetShortcut ( aFE
, aSTG
);
908 NS_WARNING ( "Not yet implemented\n" );
915 // Given a unicode string, we ensure that it contains only characters which are valid within
916 // the file system. Remove all forbidden characters from the name, and completely disallow
917 // any title that starts with a forbidden name and extension (e.g. "nul" is invalid, but
918 // "nul." and "nul.txt" are also invalid and will cause problems).
920 // It would seem that this is more functionality suited to being in nsIFile.
923 MangleTextToValidFilename(nsString
& aText
)
925 static const char* forbiddenNames
[] = {
926 "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
927 "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
928 "CON", "PRN", "AUX", "NUL", "CLOCK$"
931 aText
.StripChars(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS
);
932 aText
.CompressWhitespace(true, true);
934 for (size_t n
= 0; n
< ArrayLength(forbiddenNames
); ++n
) {
935 nameLen
= (uint32_t) strlen(forbiddenNames
[n
]);
936 if (aText
.EqualsIgnoreCase(forbiddenNames
[n
], nameLen
)) {
937 // invalid name is either the entire string, or a prefix with a period
938 if (aText
.Length() == nameLen
|| aText
.CharAt(nameLen
) == char16_t('.')) {
947 // Given a unicode string, convert it down to a valid local charset filename
948 // with the supplied extension. This ensures that we do not cut MBCS characters
951 // It would seem that this is more functionality suited to being in nsIFile.
954 CreateFilenameFromTextA(nsString
& aText
, const char * aExtension
,
955 char * aFilename
, uint32_t aFilenameLen
)
957 // ensure that the supplied name doesn't have invalid characters. If
958 // a valid mangled filename couldn't be created then it will leave the
960 MangleTextToValidFilename(aText
);
964 // repeatably call WideCharToMultiByte as long as the title doesn't fit in the buffer
965 // available to us. Continually reduce the length of the source title until the MBCS
966 // version will fit in the buffer with room for the supplied extension. Doing it this
967 // way ensures that even in MBCS environments there will be a valid MBCS filename of
968 // the correct length.
969 int maxUsableFilenameLen
= aFilenameLen
- strlen(aExtension
) - 1; // space for ext + null byte
970 int currLen
, textLen
= (int) std::min(aText
.Length(), aFilenameLen
);
971 char defaultChar
= '_';
973 currLen
= WideCharToMultiByte(CP_ACP
,
974 WC_COMPOSITECHECK
|WC_DEFAULTCHAR
,
975 aText
.get(), textLen
--, aFilename
, maxUsableFilenameLen
, &defaultChar
, nullptr);
977 while (currLen
== 0 && textLen
> 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER
);
978 if (currLen
> 0 && textLen
> 0) {
979 strcpy(&aFilename
[currLen
], aExtension
);
983 // empty names aren't permitted
989 CreateFilenameFromTextW(nsString
& aText
, const wchar_t * aExtension
,
990 wchar_t * aFilename
, uint32_t aFilenameLen
)
992 // ensure that the supplied name doesn't have invalid characters. If
993 // a valid mangled filename couldn't be created then it will leave the
995 MangleTextToValidFilename(aText
);
999 const int extensionLen
= wcslen(aExtension
);
1000 if (aText
.Length() + extensionLen
+ 1 > aFilenameLen
)
1001 aText
.Truncate(aFilenameLen
- extensionLen
- 1);
1002 wcscpy(&aFilename
[0], aText
.get());
1003 wcscpy(&aFilename
[aText
.Length()], aExtension
);
1007 #define PAGEINFO_PROPERTIES "chrome://navigator/locale/pageInfo.properties"
1010 GetLocalizedString(const char16_t
* aName
, nsXPIDLString
& aString
)
1012 nsCOMPtr
<nsIStringBundleService
> stringService
=
1013 mozilla::services::GetStringBundleService();
1017 nsCOMPtr
<nsIStringBundle
> stringBundle
;
1018 nsresult rv
= stringService
->CreateBundle(PAGEINFO_PROPERTIES
,
1019 getter_AddRefs(stringBundle
));
1023 rv
= stringBundle
->GetStringFromName(aName
, getter_Copies(aString
));
1024 return NS_SUCCEEDED(rv
);
1028 // GetFileDescriptorInternetShortcut
1030 // Create the special format for an internet shortcut and build up the data
1031 // structures the shell is expecting.
1034 nsDataObj :: GetFileDescriptorInternetShortcutA ( FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1036 // get the title of the shortcut
1038 if ( NS_FAILED(ExtractShortcutTitle(title
)) )
1039 return E_OUTOFMEMORY
;
1041 HGLOBAL fileGroupDescHandle
= ::GlobalAlloc(GMEM_ZEROINIT
|GMEM_SHARE
,sizeof(FILEGROUPDESCRIPTORA
));
1042 if (!fileGroupDescHandle
)
1043 return E_OUTOFMEMORY
;
1045 LPFILEGROUPDESCRIPTORA fileGroupDescA
= reinterpret_cast<LPFILEGROUPDESCRIPTORA
>(::GlobalLock(fileGroupDescHandle
));
1046 if (!fileGroupDescA
) {
1047 ::GlobalFree(fileGroupDescHandle
);
1048 return E_OUTOFMEMORY
;
1051 // get a valid filename in the following order: 1) from the page title,
1052 // 2) localized string for an untitled page, 3) just use "Untitled.URL"
1053 if (!CreateFilenameFromTextA(title
, ".URL",
1054 fileGroupDescA
->fgd
[0].cFileName
, NS_MAX_FILEDESCRIPTOR
)) {
1055 nsXPIDLString untitled
;
1056 if (!GetLocalizedString(MOZ_UTF16("noPageTitle"), untitled
) ||
1057 !CreateFilenameFromTextA(untitled
, ".URL",
1058 fileGroupDescA
->fgd
[0].cFileName
, NS_MAX_FILEDESCRIPTOR
)) {
1059 strcpy(fileGroupDescA
->fgd
[0].cFileName
, "Untitled.URL");
1063 // one file in the file block
1064 fileGroupDescA
->cItems
= 1;
1065 fileGroupDescA
->fgd
[0].dwFlags
= FD_LINKUI
;
1067 ::GlobalUnlock( fileGroupDescHandle
);
1068 aSTG
.hGlobal
= fileGroupDescHandle
;
1069 aSTG
.tymed
= TYMED_HGLOBAL
;
1072 } // GetFileDescriptorInternetShortcutA
1075 nsDataObj :: GetFileDescriptorInternetShortcutW ( FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1077 // get the title of the shortcut
1079 if ( NS_FAILED(ExtractShortcutTitle(title
)) )
1080 return E_OUTOFMEMORY
;
1082 HGLOBAL fileGroupDescHandle
= ::GlobalAlloc(GMEM_ZEROINIT
|GMEM_SHARE
,sizeof(FILEGROUPDESCRIPTORW
));
1083 if (!fileGroupDescHandle
)
1084 return E_OUTOFMEMORY
;
1086 LPFILEGROUPDESCRIPTORW fileGroupDescW
= reinterpret_cast<LPFILEGROUPDESCRIPTORW
>(::GlobalLock(fileGroupDescHandle
));
1087 if (!fileGroupDescW
) {
1088 ::GlobalFree(fileGroupDescHandle
);
1089 return E_OUTOFMEMORY
;
1092 // get a valid filename in the following order: 1) from the page title,
1093 // 2) localized string for an untitled page, 3) just use "Untitled.URL"
1094 if (!CreateFilenameFromTextW(title
, L
".URL",
1095 fileGroupDescW
->fgd
[0].cFileName
, NS_MAX_FILEDESCRIPTOR
)) {
1096 nsXPIDLString untitled
;
1097 if (!GetLocalizedString(MOZ_UTF16("noPageTitle"), untitled
) ||
1098 !CreateFilenameFromTextW(untitled
, L
".URL",
1099 fileGroupDescW
->fgd
[0].cFileName
, NS_MAX_FILEDESCRIPTOR
)) {
1100 wcscpy(fileGroupDescW
->fgd
[0].cFileName
, L
"Untitled.URL");
1104 // one file in the file block
1105 fileGroupDescW
->cItems
= 1;
1106 fileGroupDescW
->fgd
[0].dwFlags
= FD_LINKUI
;
1108 ::GlobalUnlock( fileGroupDescHandle
);
1109 aSTG
.hGlobal
= fileGroupDescHandle
;
1110 aSTG
.tymed
= TYMED_HGLOBAL
;
1113 } // GetFileDescriptorInternetShortcutW
1117 // GetFileContentsInternetShortcut
1119 // Create the special format for an internet shortcut and build up the data
1120 // structures the shell is expecting.
1123 nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1125 static const char * kShellIconPref
= "browser.shell.shortcutFavicons";
1127 if ( NS_FAILED(ExtractShortcutURL(url
)) )
1128 return E_OUTOFMEMORY
;
1130 // will need to change if we ever support iDNS
1131 nsAutoCString asciiUrl
;
1132 LossyCopyUTF16toASCII(url
, asciiUrl
);
1134 nsCOMPtr
<nsIFile
> icoFile
;
1135 nsCOMPtr
<nsIURI
> aUri
;
1136 NS_NewURI(getter_AddRefs(aUri
), url
);
1138 const char *shortcutFormatStr
;
1141 if (!Preferences::GetBool(kShellIconPref
, true) ||
1142 !IsVistaOrLater()) {
1143 shortcutFormatStr
= "[InternetShortcut]\r\nURL=%s\r\n";
1144 const int formatLen
= strlen(shortcutFormatStr
) - 2; // don't include %s
1145 totalLen
= formatLen
+ asciiUrl
.Length(); // don't include null character
1147 nsCOMPtr
<nsIFile
> icoFile
;
1148 nsCOMPtr
<nsIURI
> aUri
;
1149 NS_NewURI(getter_AddRefs(aUri
), url
);
1151 nsAutoString aUriHash
;
1153 mozilla::widget::FaviconHelper::ObtainCachedIconFile(aUri
, aUriHash
, mIOThread
, true);
1155 nsresult rv
= mozilla::widget::FaviconHelper::GetOutputIconPath(aUri
, icoFile
, true);
1156 NS_ENSURE_SUCCESS(rv
, E_FAIL
);
1157 rv
= icoFile
->GetNativePath(path
);
1158 NS_ENSURE_SUCCESS(rv
, E_FAIL
);
1160 shortcutFormatStr
= "[InternetShortcut]\r\nURL=%s\r\n"
1161 "IDList=\r\nHotKey=0\r\nIconFile=%s\r\n"
1163 const int formatLen
= strlen(shortcutFormatStr
) - 2 * 2; // no %s twice
1164 totalLen
= formatLen
+ asciiUrl
.Length() +
1165 path
.Length(); // we don't want a null character on the end
1168 // create a global memory area and build up the file contents w/in it
1169 HGLOBAL hGlobalMemory
= ::GlobalAlloc(GMEM_SHARE
, totalLen
);
1170 if ( !hGlobalMemory
)
1171 return E_OUTOFMEMORY
;
1173 char* contents
= reinterpret_cast<char*>(::GlobalLock(hGlobalMemory
));
1175 ::GlobalFree( hGlobalMemory
);
1176 return E_OUTOFMEMORY
;
1179 //NOTE: we intentionally use the Microsoft version of snprintf here because it does NOT null
1180 // terminate strings which reach the maximum size of the buffer. Since we know that the
1181 // formatted length here is totalLen, this call to _snprintf will format the string into
1182 // the buffer without appending the null character.
1184 if (!Preferences::GetBool(kShellIconPref
, true)) {
1185 _snprintf(contents
, totalLen
, shortcutFormatStr
, asciiUrl
.get());
1187 _snprintf(contents
, totalLen
, shortcutFormatStr
, asciiUrl
.get(), path
.get());
1190 ::GlobalUnlock(hGlobalMemory
);
1191 aSTG
.hGlobal
= hGlobalMemory
;
1192 aSTG
.tymed
= TYMED_HGLOBAL
;
1195 } // GetFileContentsInternetShortcut
1197 // check if specified flavour is present in the transferable
1198 bool nsDataObj :: IsFlavourPresent(const char *inFlavour
)
1200 bool retval
= false;
1201 NS_ENSURE_TRUE(mTransferable
, false);
1203 // get the list of flavors available in the transferable
1204 nsCOMPtr
<nsISupportsArray
> flavorList
;
1205 mTransferable
->FlavorsTransferableCanExport(getter_AddRefs(flavorList
));
1206 NS_ENSURE_TRUE(flavorList
, false);
1208 // try to find requested flavour
1210 flavorList
->Count(&cnt
);
1211 for (uint32_t i
= 0; i
< cnt
; ++i
) {
1212 nsCOMPtr
<nsISupports
> genericFlavor
;
1213 flavorList
->GetElementAt (i
, getter_AddRefs(genericFlavor
));
1214 nsCOMPtr
<nsISupportsCString
> currentFlavor (do_QueryInterface(genericFlavor
));
1215 if (currentFlavor
) {
1216 nsAutoCString flavorStr
;
1217 currentFlavor
->GetData(flavorStr
);
1218 if (flavorStr
.Equals(inFlavour
)) {
1219 retval
= true; // found it!
1223 } // for each flavor
1228 HRESULT
nsDataObj::GetPreferredDropEffect ( FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1231 aSTG
.tymed
= TYMED_HGLOBAL
;
1232 aSTG
.pUnkForRelease
= nullptr;
1233 HGLOBAL hGlobalMemory
= nullptr;
1234 hGlobalMemory
= ::GlobalAlloc(GMEM_MOVEABLE
, sizeof(DWORD
));
1235 if (hGlobalMemory
) {
1236 DWORD
* pdw
= (DWORD
*) GlobalLock(hGlobalMemory
);
1237 // The PreferredDropEffect clipboard format is only registered if a drag/drop
1238 // of an image happens from Mozilla to the desktop. We want its value
1239 // to be DROPEFFECT_MOVE in that case so that the file is moved from the
1240 // temporary location, not copied.
1241 // This value should, ideally, be set on the data object via SetData() but
1242 // our IDataObject implementation doesn't implement SetData. It adds data
1243 // to the data object lazily only when the drop target asks for it.
1244 *pdw
= (DWORD
) DROPEFFECT_MOVE
;
1245 GlobalUnlock(hGlobalMemory
);
1248 res
= E_OUTOFMEMORY
;
1250 aSTG
.hGlobal
= hGlobalMemory
;
1254 //-----------------------------------------------------
1255 HRESULT
nsDataObj::GetText(const nsACString
& aDataFlavor
, FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1257 void* data
= nullptr;
1260 // if someone asks for text/plain, look up text/unicode instead in the transferable.
1261 const char* flavorStr
;
1262 const nsPromiseFlatCString
& flat
= PromiseFlatCString(aDataFlavor
);
1263 if (aDataFlavor
.EqualsLiteral("text/plain"))
1264 flavorStr
= kUnicodeMime
;
1266 flavorStr
= flat
.get();
1268 // NOTE: CreateDataFromPrimitive creates new memory, that needs to be deleted
1269 nsCOMPtr
<nsISupports
> genericDataWrapper
;
1270 mTransferable
->GetTransferData(flavorStr
, getter_AddRefs(genericDataWrapper
), &len
);
1273 nsPrimitiveHelpers::CreateDataFromPrimitive ( flavorStr
, genericDataWrapper
, &data
, len
);
1277 HGLOBAL hGlobalMemory
= nullptr;
1279 aSTG
.tymed
= TYMED_HGLOBAL
;
1280 aSTG
.pUnkForRelease
= nullptr;
1282 // We play games under the hood and advertise flavors that we know we
1283 // can support, only they require a bit of conversion or munging of the data.
1286 // The transferable gives us data that is null-terminated, but this isn't reflected in
1287 // the |len| parameter. Windoze apps expect this null to be there so bump our data buffer
1288 // by the appropriate size to account for the null (one char for CF_TEXT, one char16_t for
1290 DWORD allocLen
= (DWORD
)len
;
1291 if ( aFE
.cfFormat
== CF_TEXT
) {
1292 // Someone is asking for text/plain; convert the unicode (assuming it's present)
1293 // to text with the correct platform encoding.
1294 size_t bufferSize
= sizeof(char)*(len
+ 2);
1295 char* plainTextData
= static_cast<char*>(nsMemory::Alloc(bufferSize
));
1296 char16_t
* castedUnicode
= reinterpret_cast<char16_t
*>(data
);
1297 int32_t plainTextLen
= WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
)castedUnicode
, len
/ 2 + 1, plainTextData
, bufferSize
, NULL
, NULL
);
1298 // replace the unicode data with our plaintext data. Recall that |plainTextLen| doesn't include
1299 // the null in the length.
1300 nsMemory::Free(data
);
1301 if ( plainTextLen
) {
1302 data
= plainTextData
;
1303 allocLen
= plainTextLen
;
1306 nsMemory::Free(plainTextData
);
1307 NS_WARNING ( "Oh no, couldn't convert unicode to plain text" );
1311 else if ( aFE
.cfFormat
== nsClipboard::CF_HTML
) {
1312 // Someone is asking for win32's HTML flavor. Convert our html fragment
1313 // from unicode to UTF-8 then put it into a format specified by msft.
1314 NS_ConvertUTF16toUTF8
converter ( reinterpret_cast<char16_t
*>(data
) );
1315 char* utf8HTML
= nullptr;
1316 nsresult rv
= BuildPlatformHTML ( converter
.get(), &utf8HTML
); // null terminates
1318 nsMemory::Free(data
);
1319 if ( NS_SUCCEEDED(rv
) && utf8HTML
) {
1320 // replace the unicode data with our HTML data. Don't forget the null.
1322 allocLen
= strlen(utf8HTML
) + sizeof(char);
1325 NS_WARNING ( "Oh no, couldn't convert to HTML" );
1330 // we assume that any data that isn't caught above is unicode. This may
1331 // be an erroneous assumption, but is true so far.
1332 allocLen
+= sizeof(char16_t
);
1335 hGlobalMemory
= (HGLOBAL
)GlobalAlloc(GMEM_MOVEABLE
, allocLen
);
1337 // Copy text to Global Memory Area
1338 if ( hGlobalMemory
) {
1339 char* dest
= reinterpret_cast<char*>(GlobalLock(hGlobalMemory
));
1340 char* source
= reinterpret_cast<char*>(data
);
1341 memcpy ( dest
, source
, allocLen
); // copies the null as well
1342 GlobalUnlock(hGlobalMemory
);
1344 aSTG
.hGlobal
= hGlobalMemory
;
1346 // Now, delete the memory that was created by CreateDataFromPrimitive (or our text/plain data)
1347 nsMemory::Free(data
);
1352 //-----------------------------------------------------
1353 HRESULT
nsDataObj::GetFile(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1359 while (NOERROR
== m_enumFE
->Next(1, &fe
, &count
)
1360 && dfInx
< mDataFlavors
.Length()) {
1361 if (mDataFlavors
[dfInx
].EqualsLiteral(kNativeImageMime
))
1362 return DropImage(aFE
, aSTG
);
1363 if (mDataFlavors
[dfInx
].EqualsLiteral(kFileMime
))
1364 return DropFile(aFE
, aSTG
);
1365 if (mDataFlavors
[dfInx
].EqualsLiteral(kFilePromiseMime
))
1366 return DropTempFile(aFE
, aSTG
);
1372 HRESULT
nsDataObj::DropFile(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1376 nsCOMPtr
<nsISupports
> genericDataWrapper
;
1378 mTransferable
->GetTransferData(kFileMime
, getter_AddRefs(genericDataWrapper
),
1380 nsCOMPtr
<nsIFile
> file ( do_QueryInterface(genericDataWrapper
) );
1384 nsCOMPtr
<nsISupportsInterfacePointer
> ptr(do_QueryInterface(genericDataWrapper
));
1386 nsCOMPtr
<nsISupports
> supports
;
1387 ptr
->GetData(getter_AddRefs(supports
));
1388 file
= do_QueryInterface(supports
);
1395 aSTG
.tymed
= TYMED_HGLOBAL
;
1396 aSTG
.pUnkForRelease
= nullptr;
1399 rv
= file
->GetPath(path
);
1403 uint32_t allocLen
= path
.Length() + 2;
1404 HGLOBAL hGlobalMemory
= nullptr;
1407 hGlobalMemory
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(DROPFILES
) +
1408 allocLen
* sizeof(char16_t
));
1412 DROPFILES
* pDropFile
= (DROPFILES
*)GlobalLock(hGlobalMemory
);
1414 // First, populate the drop file structure
1415 pDropFile
->pFiles
= sizeof(DROPFILES
); //Offset to start of file name string
1417 pDropFile
->pt
.x
= 0;
1418 pDropFile
->pt
.y
= 0;
1419 pDropFile
->fWide
= TRUE
;
1421 // Copy the filename right after the DROPFILES structure
1422 dest
= (char16_t
*)(((char*)pDropFile
) + pDropFile
->pFiles
);
1423 memcpy(dest
, path
.get(), (allocLen
- 1) * sizeof(char16_t
));
1425 // Two null characters are needed at the end of the file name.
1426 // Lookup the CF_HDROP shell clipboard format for more info.
1427 // Add the second null character right after the first one.
1428 dest
[allocLen
- 1] = L
'\0';
1430 GlobalUnlock(hGlobalMemory
);
1432 aSTG
.hGlobal
= hGlobalMemory
;
1437 HRESULT
nsDataObj::DropImage(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1440 if (!mCachedTempFile
) {
1442 nsCOMPtr
<nsISupports
> genericDataWrapper
;
1444 mTransferable
->GetTransferData(kNativeImageMime
, getter_AddRefs(genericDataWrapper
), &len
);
1445 nsCOMPtr
<imgIContainer
> image(do_QueryInterface(genericDataWrapper
));
1448 // Check if the image was put in an nsISupportsInterfacePointer wrapper.
1449 // This might not be necessary any more, but could be useful for backwards
1451 nsCOMPtr
<nsISupportsInterfacePointer
> ptr(do_QueryInterface(genericDataWrapper
));
1453 nsCOMPtr
<nsISupports
> supports
;
1454 ptr
->GetData(getter_AddRefs(supports
));
1455 image
= do_QueryInterface(supports
);
1462 // Use the clipboard helper class to build up a memory bitmap.
1463 nsImageToClipboard
converter(image
);
1464 HANDLE bits
= nullptr;
1465 rv
= converter
.GetPicture(&bits
); // Clipboard routines return a global handle we own.
1467 if (NS_FAILED(rv
) || !bits
)
1470 // We now own these bits!
1471 uint32_t bitmapSize
= GlobalSize(bits
);
1477 // Save the bitmap to a temporary location.
1478 nsCOMPtr
<nsIFile
> dropFile
;
1479 rv
= NS_GetSpecialDirectory(NS_OS_TEMP_DIR
, getter_AddRefs(dropFile
));
1485 // Filename must be random so as not to confuse apps like
1486 // Photoshop which handle multiple drags into a single window.
1489 NS_MakeRandomString(buf
, 8);
1490 memcpy(buf
+8, ".bmp", 5);
1491 filename
.Append(nsDependentCString(buf
, 12));
1492 dropFile
->AppendNative(filename
);
1493 rv
= dropFile
->CreateUnique(nsIFile::NORMAL_FILE_TYPE
, 0660);
1494 if (NS_FAILED(rv
)) {
1499 // Cache the temp file so we can delete it later and so
1500 // it doesn't get recreated over and over on multiple calls
1501 // which does occur from windows shell.
1502 dropFile
->Clone(getter_AddRefs(mCachedTempFile
));
1504 // Write the data to disk.
1505 nsCOMPtr
<nsIOutputStream
> outStream
;
1506 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outStream
), dropFile
);
1507 if (NS_FAILED(rv
)) {
1512 char * bm
= (char *)GlobalLock(bits
);
1514 BITMAPFILEHEADER fileHdr
;
1515 BITMAPINFOHEADER
*bmpHdr
= (BITMAPINFOHEADER
*)bm
;
1517 fileHdr
.bfType
= ((WORD
) ('M' << 8) | 'B');
1518 fileHdr
.bfSize
= GlobalSize (bits
) + sizeof(fileHdr
);
1519 fileHdr
.bfReserved1
= 0;
1520 fileHdr
.bfReserved2
= 0;
1521 fileHdr
.bfOffBits
= (DWORD
) (sizeof(fileHdr
) + bmpHdr
->biSize
);
1523 uint32_t writeCount
= 0;
1524 if (NS_FAILED(outStream
->Write((const char *)&fileHdr
, sizeof(fileHdr
), &writeCount
)) ||
1525 NS_FAILED(outStream
->Write((const char *)bm
, bitmapSize
, &writeCount
)))
1526 rv
= NS_ERROR_FAILURE
;
1537 // Pass the file name back to the drop target so that it can access the file.
1539 rv
= mCachedTempFile
->GetPath(path
);
1543 // Two null characters are needed to terminate the file name list.
1544 HGLOBAL hGlobalMemory
= nullptr;
1546 uint32_t allocLen
= path
.Length() + 2;
1548 aSTG
.tymed
= TYMED_HGLOBAL
;
1549 aSTG
.pUnkForRelease
= nullptr;
1551 hGlobalMemory
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(DROPFILES
) + allocLen
* sizeof(char16_t
));
1555 DROPFILES
* pDropFile
= (DROPFILES
*)GlobalLock(hGlobalMemory
);
1557 // First, populate the drop file structure.
1558 pDropFile
->pFiles
= sizeof(DROPFILES
); // Offset to start of file name char array.
1560 pDropFile
->pt
.x
= 0;
1561 pDropFile
->pt
.y
= 0;
1562 pDropFile
->fWide
= TRUE
;
1564 // Copy the filename right after the DROPFILES structure.
1565 char16_t
* dest
= (char16_t
*)(((char*)pDropFile
) + pDropFile
->pFiles
);
1566 memcpy(dest
, path
.get(), (allocLen
- 1) * sizeof(char16_t
)); // Copies the null character in path as well.
1568 // Two null characters are needed at the end of the file name.
1569 // Lookup the CF_HDROP shell clipboard format for more info.
1570 // Add the second null character right after the first one.
1571 dest
[allocLen
- 1] = L
'\0';
1573 GlobalUnlock(hGlobalMemory
);
1575 aSTG
.hGlobal
= hGlobalMemory
;
1580 HRESULT
nsDataObj::DropTempFile(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1583 if (!mCachedTempFile
) {
1584 // Tempfile will need a temporary location.
1585 nsCOMPtr
<nsIFile
> dropFile
;
1586 rv
= NS_GetSpecialDirectory(NS_OS_TEMP_DIR
, getter_AddRefs(dropFile
));
1590 // Filename must be random
1592 nsAutoString wideFileName
;
1593 nsCOMPtr
<nsIURI
> sourceURI
;
1595 res
= GetDownloadDetails(getter_AddRefs(sourceURI
),
1599 NS_UTF16ToCString(wideFileName
, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM
, filename
);
1601 dropFile
->AppendNative(filename
);
1602 rv
= dropFile
->CreateUnique(nsIFile::NORMAL_FILE_TYPE
, 0660);
1606 // Cache the temp file so we can delete it later and so
1607 // it doesn't get recreated over and over on multiple calls
1608 // which does occur from windows shell.
1609 dropFile
->Clone(getter_AddRefs(mCachedTempFile
));
1611 // Write the data to disk.
1612 nsCOMPtr
<nsIOutputStream
> outStream
;
1613 rv
= NS_NewLocalFileOutputStream(getter_AddRefs(outStream
), dropFile
);
1617 IStream
*pStream
= nullptr;
1618 nsDataObj::CreateStream(&pStream
);
1619 NS_ENSURE_TRUE(pStream
, E_FAIL
);
1622 ULONG readCount
= 0;
1623 uint32_t writeCount
= 0;
1625 HRESULT hres
= pStream
->Read(buffer
, sizeof(buffer
), &readCount
);
1630 rv
= outStream
->Write(buffer
, readCount
, &writeCount
);
1638 // Pass the file name back to the drop target so that it can access the file.
1640 rv
= mCachedTempFile
->GetPath(path
);
1644 uint32_t allocLen
= path
.Length() + 2;
1646 // Two null characters are needed to terminate the file name list.
1647 HGLOBAL hGlobalMemory
= nullptr;
1649 aSTG
.tymed
= TYMED_HGLOBAL
;
1650 aSTG
.pUnkForRelease
= nullptr;
1652 hGlobalMemory
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(DROPFILES
) + allocLen
* sizeof(char16_t
));
1656 DROPFILES
* pDropFile
= (DROPFILES
*)GlobalLock(hGlobalMemory
);
1658 // First, populate the drop file structure.
1659 pDropFile
->pFiles
= sizeof(DROPFILES
); // Offset to start of file name char array.
1661 pDropFile
->pt
.x
= 0;
1662 pDropFile
->pt
.y
= 0;
1663 pDropFile
->fWide
= TRUE
;
1665 // Copy the filename right after the DROPFILES structure.
1666 char16_t
* dest
= (char16_t
*)(((char*)pDropFile
) + pDropFile
->pFiles
);
1667 memcpy(dest
, path
.get(), (allocLen
- 1) * sizeof(char16_t
)); // Copies the null character in path as well.
1669 // Two null characters are needed at the end of the file name.
1670 // Lookup the CF_HDROP shell clipboard format for more info.
1671 // Add the second null character right after the first one.
1672 dest
[allocLen
- 1] = L
'\0';
1674 GlobalUnlock(hGlobalMemory
);
1676 aSTG
.hGlobal
= hGlobalMemory
;
1681 //-----------------------------------------------------
1682 HRESULT
nsDataObj::GetMetafilePict(FORMATETC
&, STGMEDIUM
&)
1687 //-----------------------------------------------------
1688 HRESULT
nsDataObj::SetBitmap(FORMATETC
&, STGMEDIUM
&)
1693 //-----------------------------------------------------
1694 HRESULT
nsDataObj::SetDib(FORMATETC
&, STGMEDIUM
&)
1699 //-----------------------------------------------------
1700 HRESULT
nsDataObj::SetText (FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1705 //-----------------------------------------------------
1706 HRESULT
nsDataObj::SetMetafilePict(FORMATETC
&, STGMEDIUM
&)
1713 //-----------------------------------------------------
1714 //-----------------------------------------------------
1715 CLSID
nsDataObj::GetClassID() const
1717 return CLSID_nsDataObj
;
1720 //-----------------------------------------------------
1721 // Registers the DataFlavor/FE pair.
1722 //-----------------------------------------------------
1723 void nsDataObj::AddDataFlavor(const char* aDataFlavor
, LPFORMATETC aFE
)
1725 // These two lists are the mapping to and from data flavors and FEs.
1726 // Later, OLE will tell us it needs a certain type of FORMATETC (text, unicode, etc)
1727 // unicode, etc), so we will look up the data flavor that corresponds to
1728 // the FE and then ask the transferable for that type of data.
1729 mDataFlavors
.AppendElement(aDataFlavor
);
1730 m_enumFE
->AddFormatEtc(aFE
);
1733 //-----------------------------------------------------
1734 // Sets the transferable object
1735 //-----------------------------------------------------
1736 void nsDataObj::SetTransferable(nsITransferable
* aTransferable
)
1738 NS_IF_RELEASE(mTransferable
);
1740 mTransferable
= aTransferable
;
1741 if (nullptr == mTransferable
) {
1745 NS_ADDREF(mTransferable
);
1754 // Roots around in the transferable for the appropriate flavor that indicates
1755 // a url and pulls out the url portion of the data. Used mostly for creating
1756 // internet shortcuts on the desktop. The url flavor is of the format:
1758 // <url> <linefeed> <page title>
1761 nsDataObj :: ExtractShortcutURL ( nsString
& outURL
)
1763 NS_ASSERTION ( mTransferable
, "We don't have a good transferable" );
1764 nsresult rv
= NS_ERROR_FAILURE
;
1767 nsCOMPtr
<nsISupports
> genericURL
;
1768 if ( NS_SUCCEEDED(mTransferable
->GetTransferData(kURLMime
, getter_AddRefs(genericURL
), &len
)) ) {
1769 nsCOMPtr
<nsISupportsString
> urlObject ( do_QueryInterface(genericURL
) );
1772 urlObject
->GetData ( url
);
1775 // find the first linefeed in the data, that's where the url ends. trunc the
1776 // result string at that point.
1777 int32_t lineIndex
= outURL
.FindChar ( '\n' );
1778 NS_ASSERTION ( lineIndex
> 0, "Format for url flavor is <url> <linefeed> <page title>" );
1779 if ( lineIndex
> 0 ) {
1780 outURL
.Truncate ( lineIndex
);
1784 } else if ( NS_SUCCEEDED(mTransferable
->GetTransferData(kURLDataMime
, getter_AddRefs(genericURL
), &len
)) ||
1785 NS_SUCCEEDED(mTransferable
->GetTransferData(kURLPrivateMime
, getter_AddRefs(genericURL
), &len
)) ) {
1786 nsCOMPtr
<nsISupportsString
> urlObject ( do_QueryInterface(genericURL
) );
1789 urlObject
->GetData ( url
);
1795 } // if found flavor
1799 } // ExtractShortcutURL
1803 // ExtractShortcutTitle
1805 // Roots around in the transferable for the appropriate flavor that indicates
1806 // a url and pulls out the title portion of the data. Used mostly for creating
1807 // internet shortcuts on the desktop. The url flavor is of the format:
1809 // <url> <linefeed> <page title>
1812 nsDataObj :: ExtractShortcutTitle ( nsString
& outTitle
)
1814 NS_ASSERTION ( mTransferable
, "We'd don't have a good transferable" );
1815 nsresult rv
= NS_ERROR_FAILURE
;
1818 nsCOMPtr
<nsISupports
> genericURL
;
1819 if ( NS_SUCCEEDED(mTransferable
->GetTransferData(kURLMime
, getter_AddRefs(genericURL
), &len
)) ) {
1820 nsCOMPtr
<nsISupportsString
> urlObject ( do_QueryInterface(genericURL
) );
1823 urlObject
->GetData ( url
);
1825 // find the first linefeed in the data, that's where the url ends. we want
1826 // everything after that linefeed. FindChar() returns -1 if we can't find
1827 int32_t lineIndex
= url
.FindChar ( '\n' );
1828 NS_ASSERTION ( lineIndex
!= -1, "Format for url flavor is <url> <linefeed> <page title>" );
1829 if ( lineIndex
!= -1 ) {
1830 url
.Mid ( outTitle
, lineIndex
+ 1, (len
/2) - (lineIndex
+ 1) );
1834 } // if found flavor
1838 } // ExtractShortcutTitle
1842 // BuildPlatformHTML
1844 // Munge our HTML data to win32's CF_HTML spec. Basically, put the requisite
1845 // header information on it. This will null terminate |outPlatformHTML|. See
1846 // http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp
1849 // We assume that |inOurHTML| is already a fragment (ie, doesn't have <HTML>
1850 // or <BODY> tags). We'll wrap the fragment with them to make other apps
1854 nsDataObj :: BuildPlatformHTML ( const char* inOurHTML
, char** outPlatformHTML
)
1856 *outPlatformHTML
= nullptr;
1858 nsDependentCString
inHTMLString(inOurHTML
);
1859 const char* const numPlaceholder
= "00000000";
1860 const char* const startHTMLPrefix
= "Version:0.9\r\nStartHTML:";
1861 const char* const endHTMLPrefix
= "\r\nEndHTML:";
1862 const char* const startFragPrefix
= "\r\nStartFragment:";
1863 const char* const endFragPrefix
= "\r\nEndFragment:";
1864 const char* const startSourceURLPrefix
= "\r\nSourceURL:";
1865 const char* const endFragTrailer
= "\r\n";
1867 // Do we already have mSourceURL from a drag?
1868 if (mSourceURL
.IsEmpty()) {
1870 ExtractShortcutURL(url
);
1872 AppendUTF16toUTF8(url
, mSourceURL
);
1875 const int32_t kSourceURLLength
= mSourceURL
.Length();
1876 const int32_t kNumberLength
= strlen(numPlaceholder
);
1878 const int32_t kTotalHeaderLen
= strlen(startHTMLPrefix
) +
1879 strlen(endHTMLPrefix
) +
1880 strlen(startFragPrefix
) +
1881 strlen(endFragPrefix
) +
1882 strlen(endFragTrailer
) +
1883 (kSourceURLLength
> 0 ? strlen(startSourceURLPrefix
) : 0) +
1885 (4 * kNumberLength
);
1887 NS_NAMED_LITERAL_CSTRING(htmlHeaderString
, "<html><body>\r\n");
1889 NS_NAMED_LITERAL_CSTRING(fragmentHeaderString
, "<!--StartFragment-->");
1891 nsDependentCString
trailingString(
1892 "<!--EndFragment-->\r\n"
1896 // calculate the offsets
1897 int32_t startHTMLOffset
= kTotalHeaderLen
;
1898 int32_t startFragOffset
= startHTMLOffset
1899 + htmlHeaderString
.Length()
1900 + fragmentHeaderString
.Length();
1902 int32_t endFragOffset
= startFragOffset
1903 + inHTMLString
.Length();
1905 int32_t endHTMLOffset
= endFragOffset
1906 + trailingString
.Length();
1908 // now build the final version
1909 nsCString clipboardString
;
1910 clipboardString
.SetCapacity(endHTMLOffset
);
1912 clipboardString
.Append(startHTMLPrefix
);
1913 clipboardString
.Append(nsPrintfCString("%08u", startHTMLOffset
));
1915 clipboardString
.Append(endHTMLPrefix
);
1916 clipboardString
.Append(nsPrintfCString("%08u", endHTMLOffset
));
1918 clipboardString
.Append(startFragPrefix
);
1919 clipboardString
.Append(nsPrintfCString("%08u", startFragOffset
));
1921 clipboardString
.Append(endFragPrefix
);
1922 clipboardString
.Append(nsPrintfCString("%08u", endFragOffset
));
1924 if (kSourceURLLength
> 0) {
1925 clipboardString
.Append(startSourceURLPrefix
);
1926 clipboardString
.Append(mSourceURL
);
1929 clipboardString
.Append(endFragTrailer
);
1931 clipboardString
.Append(htmlHeaderString
);
1932 clipboardString
.Append(fragmentHeaderString
);
1933 clipboardString
.Append(inHTMLString
);
1934 clipboardString
.Append(trailingString
);
1936 *outPlatformHTML
= ToNewCString(clipboardString
);
1937 if (!*outPlatformHTML
)
1938 return NS_ERROR_OUT_OF_MEMORY
;
1944 nsDataObj :: GetUniformResourceLocator( FORMATETC
& aFE
, STGMEDIUM
& aSTG
, bool aIsUnicode
)
1947 if (IsFlavourPresent(kURLMime
)) {
1949 res
= ExtractUniformResourceLocatorW( aFE
, aSTG
);
1951 res
= ExtractUniformResourceLocatorA( aFE
, aSTG
);
1954 NS_WARNING ("Not yet implemented\n");
1959 nsDataObj::ExtractUniformResourceLocatorA(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1961 HRESULT result
= S_OK
;
1964 if (NS_FAILED(ExtractShortcutURL(url
)))
1965 return E_OUTOFMEMORY
;
1967 NS_LossyConvertUTF16toASCII
asciiUrl(url
);
1968 const int totalLen
= asciiUrl
.Length() + 1;
1969 HGLOBAL hGlobalMemory
= GlobalAlloc(GMEM_ZEROINIT
|GMEM_SHARE
, totalLen
);
1971 return E_OUTOFMEMORY
;
1973 char* contents
= reinterpret_cast<char*>(GlobalLock(hGlobalMemory
));
1975 GlobalFree(hGlobalMemory
);
1976 return E_OUTOFMEMORY
;
1979 strcpy(contents
, asciiUrl
.get());
1980 GlobalUnlock(hGlobalMemory
);
1981 aSTG
.hGlobal
= hGlobalMemory
;
1982 aSTG
.tymed
= TYMED_HGLOBAL
;
1988 nsDataObj::ExtractUniformResourceLocatorW(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
1990 HRESULT result
= S_OK
;
1993 if (NS_FAILED(ExtractShortcutURL(url
)))
1994 return E_OUTOFMEMORY
;
1996 const int totalLen
= (url
.Length() + 1) * sizeof(char16_t
);
1997 HGLOBAL hGlobalMemory
= GlobalAlloc(GMEM_ZEROINIT
|GMEM_SHARE
, totalLen
);
1999 return E_OUTOFMEMORY
;
2001 wchar_t* contents
= reinterpret_cast<wchar_t*>(GlobalLock(hGlobalMemory
));
2003 GlobalFree(hGlobalMemory
);
2004 return E_OUTOFMEMORY
;
2007 wcscpy(contents
, url
.get());
2008 GlobalUnlock(hGlobalMemory
);
2009 aSTG
.hGlobal
= hGlobalMemory
;
2010 aSTG
.tymed
= TYMED_HGLOBAL
;
2016 // Gets the filename from the kFilePromiseURLMime flavour
2017 HRESULT
nsDataObj::GetDownloadDetails(nsIURI
**aSourceURI
,
2018 nsAString
&aFilename
)
2020 *aSourceURI
= nullptr;
2022 NS_ENSURE_TRUE(mTransferable
, E_FAIL
);
2024 // get the URI from the kFilePromiseURLMime flavor
2025 nsCOMPtr
<nsISupports
> urlPrimitive
;
2026 uint32_t dataSize
= 0;
2027 mTransferable
->GetTransferData(kFilePromiseURLMime
, getter_AddRefs(urlPrimitive
), &dataSize
);
2028 nsCOMPtr
<nsISupportsString
> srcUrlPrimitive
= do_QueryInterface(urlPrimitive
);
2029 NS_ENSURE_TRUE(srcUrlPrimitive
, E_FAIL
);
2031 nsAutoString srcUri
;
2032 srcUrlPrimitive
->GetData(srcUri
);
2033 if (srcUri
.IsEmpty())
2035 nsCOMPtr
<nsIURI
> sourceURI
;
2036 NS_NewURI(getter_AddRefs(sourceURI
), srcUri
);
2038 nsAutoString srcFileName
;
2039 nsCOMPtr
<nsISupports
> fileNamePrimitive
;
2040 mTransferable
->GetTransferData(kFilePromiseDestFilename
, getter_AddRefs(fileNamePrimitive
), &dataSize
);
2041 nsCOMPtr
<nsISupportsString
> srcFileNamePrimitive
= do_QueryInterface(fileNamePrimitive
);
2042 if (srcFileNamePrimitive
) {
2043 srcFileNamePrimitive
->GetData(srcFileName
);
2045 nsCOMPtr
<nsIURL
> sourceURL
= do_QueryInterface(sourceURI
);
2049 nsAutoCString urlFileName
;
2050 sourceURL
->GetFileName(urlFileName
);
2051 NS_UnescapeURL(urlFileName
);
2052 CopyUTF8toUTF16(urlFileName
, srcFileName
);
2054 if (srcFileName
.IsEmpty())
2057 // make the name safe for the filesystem
2058 MangleTextToValidFilename(srcFileName
);
2060 sourceURI
.swap(*aSourceURI
);
2061 aFilename
= srcFileName
;
2065 HRESULT
nsDataObj::GetFileDescriptor_IStreamA(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
2067 HGLOBAL fileGroupDescHandle
= ::GlobalAlloc(GMEM_ZEROINIT
|GMEM_SHARE
,sizeof(FILEGROUPDESCRIPTORW
));
2068 NS_ENSURE_TRUE(fileGroupDescHandle
, E_OUTOFMEMORY
);
2070 LPFILEGROUPDESCRIPTORA fileGroupDescA
= reinterpret_cast<LPFILEGROUPDESCRIPTORA
>(GlobalLock(fileGroupDescHandle
));
2071 if (!fileGroupDescA
) {
2072 ::GlobalFree(fileGroupDescHandle
);
2073 return E_OUTOFMEMORY
;
2076 nsAutoString wideFileName
;
2078 nsCOMPtr
<nsIURI
> sourceURI
;
2079 res
= GetDownloadDetails(getter_AddRefs(sourceURI
), wideFileName
);
2082 ::GlobalFree(fileGroupDescHandle
);
2086 nsAutoCString nativeFileName
;
2087 NS_UTF16ToCString(wideFileName
, NS_CSTRING_ENCODING_NATIVE_FILESYSTEM
, nativeFileName
);
2089 strncpy(fileGroupDescA
->fgd
[0].cFileName
, nativeFileName
.get(), NS_MAX_FILEDESCRIPTOR
- 1);
2090 fileGroupDescA
->fgd
[0].cFileName
[NS_MAX_FILEDESCRIPTOR
- 1] = '\0';
2092 // one file in the file block
2093 fileGroupDescA
->cItems
= 1;
2094 fileGroupDescA
->fgd
[0].dwFlags
= FD_PROGRESSUI
;
2096 GlobalUnlock( fileGroupDescHandle
);
2097 aSTG
.hGlobal
= fileGroupDescHandle
;
2098 aSTG
.tymed
= TYMED_HGLOBAL
;
2103 HRESULT
nsDataObj::GetFileDescriptor_IStreamW(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
2105 HGLOBAL fileGroupDescHandle
= ::GlobalAlloc(GMEM_ZEROINIT
|GMEM_SHARE
,sizeof(FILEGROUPDESCRIPTORW
));
2106 NS_ENSURE_TRUE(fileGroupDescHandle
, E_OUTOFMEMORY
);
2108 LPFILEGROUPDESCRIPTORW fileGroupDescW
= reinterpret_cast<LPFILEGROUPDESCRIPTORW
>(GlobalLock(fileGroupDescHandle
));
2109 if (!fileGroupDescW
) {
2110 ::GlobalFree(fileGroupDescHandle
);
2111 return E_OUTOFMEMORY
;
2114 nsAutoString wideFileName
;
2116 nsCOMPtr
<nsIURI
> sourceURI
;
2117 res
= GetDownloadDetails(getter_AddRefs(sourceURI
),
2121 ::GlobalFree(fileGroupDescHandle
);
2125 wcsncpy(fileGroupDescW
->fgd
[0].cFileName
, wideFileName
.get(), NS_MAX_FILEDESCRIPTOR
- 1);
2126 fileGroupDescW
->fgd
[0].cFileName
[NS_MAX_FILEDESCRIPTOR
- 1] = '\0';
2127 // one file in the file block
2128 fileGroupDescW
->cItems
= 1;
2129 fileGroupDescW
->fgd
[0].dwFlags
= FD_PROGRESSUI
;
2131 GlobalUnlock(fileGroupDescHandle
);
2132 aSTG
.hGlobal
= fileGroupDescHandle
;
2133 aSTG
.tymed
= TYMED_HGLOBAL
;
2138 HRESULT
nsDataObj::GetFileContents_IStream(FORMATETC
& aFE
, STGMEDIUM
& aSTG
)
2140 IStream
*pStream
= nullptr;
2142 nsDataObj::CreateStream(&pStream
);
2143 NS_ENSURE_TRUE(pStream
, E_FAIL
);
2145 aSTG
.tymed
= TYMED_ISTREAM
;
2146 aSTG
.pstm
= pStream
;
2147 aSTG
.pUnkForRelease
= nullptr;
2152 void nsDataObj::RemoveTempFile(nsITimer
* aTimer
, void* aClosure
)
2154 nsDataObj
*timedDataObj
= static_cast<nsDataObj
*>(aClosure
);
2155 if (timedDataObj
->mCachedTempFile
) {
2156 timedDataObj
->mCachedTempFile
->Remove(false);
2157 timedDataObj
->mCachedTempFile
= nullptr;
2159 timedDataObj
->Release();