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/. */
5 
6 #ifndef _NSDATAOBJ_H_
7 #define _NSDATAOBJ_H_
8 
9 #include <oleidl.h>
10 #include <shldisp.h>
11 
12 #include "mozilla/glue/WinUtils.h"
13 #include "nsCOMPtr.h"
14 #include "nsString.h"
15 #include "nsIFile.h"
16 #include "nsIURI.h"
17 #include "nsIStreamListener.h"
18 #include "nsIChannel.h"
19 #include "nsCOMArray.h"
20 #include "nsITimer.h"
21 #include "nsIURI.h"
22 #include "nsString.h"
23 #include "nsWindowsHelpers.h"
24 
25 class nsICookieJarSettings;
26 class nsIThread;
27 class nsIPrincipal;
28 class CEnumFormatEtc;
29 class nsITransferable;
30 
31 /*
32  * This ole registered class is used to facilitate drag-drop of objects which
33  * can be adapted by an object derived from CfDragDrop. The CfDragDrop is
34  * associated with instances via SetDragDrop().
35  */
36 class nsDataObj : public IDataObject, public IDataObjectAsyncCapability {
37   nsCOMPtr<nsIThread> mIOThread;
38 
39  public:  // construction, destruction
40   explicit nsDataObj(nsIURI* uri = nullptr);
41 
42  protected:
43   virtual ~nsDataObj();
44 
45  public:  // IUnknown methods - see iunknown.h for documentation
46   STDMETHODIMP_(ULONG) AddRef() override;
47   STDMETHODIMP QueryInterface(REFIID, void**) override;
48   STDMETHODIMP_(ULONG) Release() override;
49 
50   // support for clipboard
51   virtual void AddDataFlavor(const char* aDataFlavor, LPFORMATETC aFE);
52   void SetTransferable(nsITransferable* aTransferable);
53 
54  public:  // IDataObject methods - these are general comments. see CfDragDrop
55           // for overriding behavior
56   // Store data in pSTM according to the format specified by pFE, if the
57   // format is supported (supported formats are specified in CfDragDrop::
58   // GetFormats) and return NOERROR; otherwise return DATA_E_FORMATETC. It
59   // is the callers responsibility to free pSTM if NOERROR is returned.
60   STDMETHODIMP GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM) override;
61 
62   // Similar to GetData except that the caller allocates the structure
63   // referenced by pSTM.
64   STDMETHODIMP GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM) override;
65 
66   // Returns S_TRUE if this object supports the format specified by pSTM,
67   // S_FALSE otherwise.
68   STDMETHODIMP QueryGetData(LPFORMATETC pFE) override;
69 
70   // Set pCanonFE to the canonical format of pFE if one exists and return
71   // NOERROR, otherwise return DATA_S_SAMEFORMATETC. A canonical format
72   // implies an identical rendering.
73   STDMETHODIMP GetCanonicalFormatEtc(LPFORMATETC pFE,
74                                      LPFORMATETC pCanonFE) final;
75 
76   // Set this objects data according to the format specified by pFE and
77   // the storage medium specified by pSTM and return NOERROR, if the format
78   // is supported. If release is TRUE this object must release the storage
79   // associated with pSTM.
80   STDMETHODIMP SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM,
81                        BOOL release) override;
82 
83   // Set ppEnum to an IEnumFORMATETC object which will iterate all of the
84   // data formats that this object supports. direction is either DATADIR_GET
85   // or DATADIR_SET.
86   STDMETHODIMP EnumFormatEtc(DWORD direction, LPENUMFORMATETC* ppEnum) final;
87 
88   // Set up an advisory connection to this object based on the format specified
89   // by pFE, flags, and the pAdvise. Set pConn to the established advise
90   // connection.
91   STDMETHODIMP DAdvise(LPFORMATETC pFE, DWORD flags, LPADVISESINK pAdvise,
92                        DWORD* pConn) final;
93 
94   // Turn off advising of a previous call to DAdvise which set pConn.
95   STDMETHODIMP DUnadvise(DWORD pConn) final;
96 
97   // Set ppEnum to an IEnumSTATDATA object which will iterate over the
98   // existing objects which have established advisory connections to this
99   // object.
100   STDMETHODIMP EnumDAdvise(LPENUMSTATDATA* ppEnum) final;
101 
102   // IDataObjectAsyncCapability methods
103   STDMETHODIMP EndOperation(HRESULT hResult, IBindCtx* pbcReserved,
104                             DWORD dwEffects) final;
105   STDMETHODIMP GetAsyncMode(BOOL* pfIsOpAsync) final;
106   STDMETHODIMP InOperation(BOOL* pfInAsyncOp) final;
107   STDMETHODIMP SetAsyncMode(BOOL fDoOpAsync) final;
108   STDMETHODIMP StartOperation(IBindCtx* pbcReserved) final;
109 
110  private:  // other methods
111   // Gets the filename from the kFilePromiseURLMime flavour
112   HRESULT GetDownloadDetails(nsIURI** aSourceURI, nsAString& aFilename);
113 
114   // help determine the kind of drag
115   bool IsFlavourPresent(const char* inFlavour);
116 
117  protected:
118   HRESULT GetFile(FORMATETC& aFE, STGMEDIUM& aSTG);
119   HRESULT GetText(const nsACString& aDF, FORMATETC& aFE, STGMEDIUM& aSTG);
120 
121  private:
122   HRESULT GetDib(const nsACString& inFlavor, FORMATETC&, STGMEDIUM& aSTG);
123 
124   HRESULT DropImage(FORMATETC& aFE, STGMEDIUM& aSTG);
125   HRESULT DropFile(FORMATETC& aFE, STGMEDIUM& aSTG);
126   HRESULT DropTempFile(FORMATETC& aFE, STGMEDIUM& aSTG);
127 
128   HRESULT GetUniformResourceLocator(FORMATETC& aFE, STGMEDIUM& aSTG,
129                                     bool aIsUnicode);
130   HRESULT ExtractUniformResourceLocatorA(FORMATETC& aFE, STGMEDIUM& aSTG);
131   HRESULT ExtractUniformResourceLocatorW(FORMATETC& aFE, STGMEDIUM& aSTG);
132   HRESULT GetFileDescriptor(FORMATETC& aFE, STGMEDIUM& aSTG, bool aIsUnicode);
133 
134  protected:
135   HRESULT GetFileContents(FORMATETC& aFE, STGMEDIUM& aSTG);
136 
137  private:
138   HRESULT GetPreferredDropEffect(FORMATETC& aFE, STGMEDIUM& aSTG);
139 
140   // Provide the structures needed for an internet shortcut by the shell
141   HRESULT GetFileDescriptorInternetShortcutA(FORMATETC& aFE, STGMEDIUM& aSTG);
142   HRESULT GetFileDescriptorInternetShortcutW(FORMATETC& aFE, STGMEDIUM& aSTG);
143   HRESULT GetFileContentsInternetShortcut(FORMATETC& aFE, STGMEDIUM& aSTG);
144 
145   // IStream implementation
146   HRESULT GetFileDescriptor_IStreamA(FORMATETC& aFE, STGMEDIUM& aSTG);
147   HRESULT GetFileDescriptor_IStreamW(FORMATETC& aFE, STGMEDIUM& aSTG);
148   HRESULT GetFileContents_IStream(FORMATETC& aFE, STGMEDIUM& aSTG);
149 
150   nsresult ExtractShortcutURL(nsString& outURL);
151   nsresult ExtractShortcutTitle(nsString& outTitle);
152 
153   // munge our HTML data to win32's CF_HTML spec. Will null terminate
154   nsresult BuildPlatformHTML(const char* inOurHTML, char** outPlatformHTML);
155 
156   // Used for the SourceURL part of CF_HTML
157   nsCString mSourceURL;
158 
159  protected:
160   BOOL FormatsMatch(const FORMATETC& source, const FORMATETC& target) const;
161 
162   ULONG m_cRef;  // the reference count
163 
164  private:
165   nsTArray<nsCString> mDataFlavors;
166 
167   nsITransferable* mTransferable;  // nsDataObj owns and ref counts
168                                    // nsITransferable, the nsITransferable does
169                                    // know anything about the nsDataObj
170 
171  protected:
172   CEnumFormatEtc* m_enumFE;  // Ownership Rules:
173                              // nsDataObj owns and ref counts CEnumFormatEtc,
174 
175  private:
176   nsCOMPtr<nsIFile> mCachedTempFile;
177   RefPtr<nsDataObj> mKeepAlive;
178 
179   BOOL mIsAsyncMode;
180   BOOL mIsInOperation;
181   ///////////////////////////////////////////////////////////////////////////////
182   // CStream class implementation
183   // this class is used in Drag and drop with download sample
184   // called from IDataObject::GetData
185   class CStreamBase : public IStream {
186     // IStream
187     STDMETHODIMP Clone(IStream** ppStream) final;
188     STDMETHODIMP Commit(DWORD dwFrags) final;
189     STDMETHODIMP CopyTo(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy,
190                         ULARGE_INTEGER* nBytesRead,
191                         ULARGE_INTEGER* nBytesWritten) final;
192     STDMETHODIMP LockRegion(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,
193                             DWORD dwFlags) final;
194     STDMETHODIMP Revert(void) final;
195     STDMETHODIMP Seek(LARGE_INTEGER nMove, DWORD dwOrigin,
196                       ULARGE_INTEGER* nNewPos) final;
197     STDMETHODIMP SetSize(ULARGE_INTEGER nNewSize) final;
198     STDMETHODIMP UnlockRegion(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,
199                               DWORD dwFlags) final;
200     STDMETHODIMP Write(const void* pvBuffer, ULONG nBytesToRead,
201                        ULONG* nBytesRead) final;
202 
203    protected:
204     uint32_t mStreamRead;
205 
206     CStreamBase();
207     virtual ~CStreamBase();
208   };
209 
210   class CStream final : public CStreamBase, public nsIStreamListener {
211     nsCOMPtr<nsIChannel> mChannel;
212     FallibleTArray<uint8_t> mChannelData;
213     nsresult mChannelResult;
214     bool mChannelRead;
215 
216     virtual ~CStream();
217     nsresult WaitForCompletion();
218 
219     // IUnknown
220     STDMETHOD(QueryInterface)(REFIID refiid, void** ppvResult) final;
221 
222     // IStream
223     STDMETHODIMP Read(void* pvBuffer, ULONG nBytesToRead,
224                       ULONG* nBytesRead) final;
225     STDMETHODIMP Stat(STATSTG* statstg, DWORD dwFlags) final;
226 
227    public:
228     CStream();
229     nsresult Init(nsIURI* pSourceURI, nsContentPolicyType aContentPolicyType,
230                   nsIPrincipal* aRequestingPrincipal,
231                   nsICookieJarSettings* aCookieJarSettings);
232 
233     NS_DECL_ISUPPORTS
234     NS_DECL_NSIREQUESTOBSERVER
235     NS_DECL_NSISTREAMLISTENER
236   };
237 
238   HRESULT CreateStream(IStream** outStream);
239 
240   // This class must be thread-safe.
241   class AutoCloseEvent final {
242     const nsAutoHandle mEvent;
243 
244     AutoCloseEvent(const AutoCloseEvent&) = delete;
245     void operator=(const AutoCloseEvent&) = delete;
246     ~AutoCloseEvent() = default;
247 
248    public:
249     AutoCloseEvent();
250     bool IsInited() const;
251     void Signal() const;
252     DWORD Wait(DWORD aMillisec) const;
253     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AutoCloseEvent)
254   };
255 
256   // This class must be thread-safe.
257   class AutoSetEvent final {
258     const RefPtr<AutoCloseEvent> mEvent;
259 
260     AutoSetEvent(const AutoSetEvent&) = delete;
261     void operator=(const AutoSetEvent&) = delete;
262     ~AutoSetEvent();
263 
264    public:
265     explicit AutoSetEvent(mozilla::NotNull<AutoCloseEvent*> aEvent);
266     void Signal() const;
267     bool IsWaiting() const;
268     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AutoSetEvent)
269   };
270 
271   // This class must be thread-safe.
272   class CMemStream final : public CStreamBase {
273     static mozilla::glue::Win32SRWLock mLock;
274     const nsAutoGlobalMem mGlobalMem;
275     const RefPtr<AutoCloseEvent> mEvent;
276     const uint32_t mTotalLength;
277     RefPtr<IUnknown> mMarshaler;
278 
279     virtual ~CMemStream();
280     void WaitForCompletion();
281 
282     // IStream
283     STDMETHODIMP Read(void* pvBuffer, ULONG nBytesToRead,
284                       ULONG* nBytesRead) final;
285     STDMETHODIMP Stat(STATSTG* statstg, DWORD dwFlags) final;
286 
287    public:
288     CMemStream(nsHGLOBAL aGlobalMem, uint32_t mTotalLength,
289                already_AddRefed<AutoCloseEvent> aEvent);
290 
291     // IUnknown
292     STDMETHOD(QueryInterface)(REFIID refiid, void** ppvResult) final;
293     NS_INLINE_DECL_THREADSAFE_VIRTUAL_REFCOUNTING(CMemStream, final)
294   };
295 
296  private:
297   // Drag and drop helper data for implementing drag and drop image support
298   typedef struct {
299     FORMATETC fe;
300     STGMEDIUM stgm;
301   } DATAENTRY, *LPDATAENTRY;
302 
303   nsTArray<LPDATAENTRY> mDataEntryList;
304   nsCOMPtr<nsITimer> mTimer;
305 
306   bool LookupArbitraryFormat(FORMATETC* aFormat, LPDATAENTRY* aDataEntry,
307                              BOOL aAddorUpdate);
308   bool CopyMediumData(STGMEDIUM* aMediumDst, STGMEDIUM* aMediumSrc,
309                       LPFORMATETC aFormat, BOOL aSetData);
310 };
311 
312 #endif  // _NSDATAOBJ_H_
313