widget/windows/nsDataObjCollection.cpp

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

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

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

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include <shlobj.h>
michael@0 7
michael@0 8 #include "nsDataObjCollection.h"
michael@0 9 #include "nsClipboard.h"
michael@0 10 #include "IEnumFE.h"
michael@0 11
michael@0 12 #include <ole2.h>
michael@0 13
michael@0 14 // {25589C3E-1FAC-47b9-BF43-CAEA89B79533}
michael@0 15 const IID IID_IDataObjCollection =
michael@0 16 {0x25589c3e, 0x1fac, 0x47b9, {0xbf, 0x43, 0xca, 0xea, 0x89, 0xb7, 0x95, 0x33}};
michael@0 17
michael@0 18 /*
michael@0 19 * Class nsDataObjCollection
michael@0 20 */
michael@0 21
michael@0 22 nsDataObjCollection::nsDataObjCollection()
michael@0 23 : m_cRef(0), mIsAsyncMode(FALSE), mIsInOperation(FALSE)
michael@0 24 {
michael@0 25 m_enumFE = new CEnumFormatEtc();
michael@0 26 m_enumFE->AddRef();
michael@0 27 }
michael@0 28
michael@0 29 nsDataObjCollection::~nsDataObjCollection()
michael@0 30 {
michael@0 31 mDataFlavors.Clear();
michael@0 32 mDataObjects.Clear();
michael@0 33
michael@0 34 m_enumFE->Release();
michael@0 35 }
michael@0 36
michael@0 37
michael@0 38 // IUnknown interface methods - see iunknown.h for documentation
michael@0 39 STDMETHODIMP nsDataObjCollection::QueryInterface(REFIID riid, void** ppv)
michael@0 40 {
michael@0 41 *ppv=nullptr;
michael@0 42
michael@0 43 if ( (IID_IUnknown == riid) || (IID_IDataObject == riid) ) {
michael@0 44 *ppv = static_cast<IDataObject*>(this);
michael@0 45 AddRef();
michael@0 46 return NOERROR;
michael@0 47 }
michael@0 48
michael@0 49 if ( IID_IDataObjCollection == riid ) {
michael@0 50 *ppv = static_cast<nsIDataObjCollection*>(this);
michael@0 51 AddRef();
michael@0 52 return NOERROR;
michael@0 53 }
michael@0 54
michael@0 55 return E_NOINTERFACE;
michael@0 56 }
michael@0 57
michael@0 58 STDMETHODIMP_(ULONG) nsDataObjCollection::AddRef()
michael@0 59 {
michael@0 60 return ++m_cRef;
michael@0 61 }
michael@0 62
michael@0 63 STDMETHODIMP_(ULONG) nsDataObjCollection::Release()
michael@0 64 {
michael@0 65 if (0 != --m_cRef)
michael@0 66 return m_cRef;
michael@0 67
michael@0 68 delete this;
michael@0 69
michael@0 70 return 0;
michael@0 71 }
michael@0 72
michael@0 73 BOOL nsDataObjCollection::FormatsMatch(const FORMATETC& source,
michael@0 74 const FORMATETC& target) const
michael@0 75 {
michael@0 76 if ((source.cfFormat == target.cfFormat) &&
michael@0 77 (source.dwAspect & target.dwAspect) &&
michael@0 78 (source.tymed & target.tymed)) {
michael@0 79 return TRUE;
michael@0 80 } else {
michael@0 81 return FALSE;
michael@0 82 }
michael@0 83 }
michael@0 84
michael@0 85 // IDataObject methods
michael@0 86 STDMETHODIMP nsDataObjCollection::GetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
michael@0 87 {
michael@0 88 static CLIPFORMAT fileDescriptorFlavorA =
michael@0 89 ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
michael@0 90 static CLIPFORMAT fileDescriptorFlavorW =
michael@0 91 ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
michael@0 92 static CLIPFORMAT fileFlavor = ::RegisterClipboardFormat(CFSTR_FILECONTENTS);
michael@0 93
michael@0 94 switch (pFE->cfFormat) {
michael@0 95 case CF_TEXT:
michael@0 96 case CF_UNICODETEXT:
michael@0 97 return GetText(pFE, pSTM);
michael@0 98 case CF_HDROP:
michael@0 99 return GetFile(pFE, pSTM);
michael@0 100 default:
michael@0 101 if (pFE->cfFormat == fileDescriptorFlavorA ||
michael@0 102 pFE->cfFormat == fileDescriptorFlavorW) {
michael@0 103 return GetFileDescriptors(pFE, pSTM);
michael@0 104 }
michael@0 105 if (pFE->cfFormat == fileFlavor) {
michael@0 106 return GetFileContents(pFE, pSTM);
michael@0 107 }
michael@0 108 }
michael@0 109 return GetFirstSupporting(pFE, pSTM);
michael@0 110 }
michael@0 111
michael@0 112 STDMETHODIMP nsDataObjCollection::GetDataHere(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
michael@0 113 {
michael@0 114 return E_FAIL;
michael@0 115 }
michael@0 116
michael@0 117 // Other objects querying to see if we support a particular format
michael@0 118 STDMETHODIMP nsDataObjCollection::QueryGetData(LPFORMATETC pFE)
michael@0 119 {
michael@0 120 UINT format = nsClipboard::GetFormat(MULTI_MIME);
michael@0 121
michael@0 122 if (format == pFE->cfFormat) {
michael@0 123 return S_OK;
michael@0 124 }
michael@0 125
michael@0 126 for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
michael@0 127 IDataObject * dataObj = mDataObjects.ElementAt(i);
michael@0 128 if (S_OK == dataObj->QueryGetData(pFE)) {
michael@0 129 return S_OK;
michael@0 130 }
michael@0 131 }
michael@0 132
michael@0 133 return DV_E_FORMATETC;
michael@0 134 }
michael@0 135
michael@0 136 STDMETHODIMP nsDataObjCollection::GetCanonicalFormatEtc(LPFORMATETC pFEIn,
michael@0 137 LPFORMATETC pFEOut)
michael@0 138 {
michael@0 139 return E_NOTIMPL;
michael@0 140 }
michael@0 141
michael@0 142 STDMETHODIMP nsDataObjCollection::SetData(LPFORMATETC pFE,
michael@0 143 LPSTGMEDIUM pSTM,
michael@0 144 BOOL fRelease)
michael@0 145 {
michael@0 146 // Set arbitrary data formats on the first object in the collection and let
michael@0 147 // it handle the heavy lifting
michael@0 148 if (mDataObjects.Length() == 0)
michael@0 149 return E_FAIL;
michael@0 150 return mDataObjects.ElementAt(0)->SetData(pFE, pSTM, fRelease);
michael@0 151 }
michael@0 152
michael@0 153 STDMETHODIMP nsDataObjCollection::EnumFormatEtc(DWORD dwDir,
michael@0 154 LPENUMFORMATETC *ppEnum)
michael@0 155 {
michael@0 156 if (dwDir == DATADIR_GET) {
michael@0 157 // Clone addref's the new enumerator.
michael@0 158 m_enumFE->Clone(ppEnum);
michael@0 159 if (!(*ppEnum))
michael@0 160 return E_FAIL;
michael@0 161 (*ppEnum)->Reset();
michael@0 162 return S_OK;
michael@0 163 }
michael@0 164
michael@0 165 return E_NOTIMPL;
michael@0 166 }
michael@0 167
michael@0 168 STDMETHODIMP nsDataObjCollection::DAdvise(LPFORMATETC pFE,
michael@0 169 DWORD dwFlags,
michael@0 170 LPADVISESINK pIAdviseSink,
michael@0 171 DWORD* pdwConn)
michael@0 172 {
michael@0 173 return OLE_E_ADVISENOTSUPPORTED;
michael@0 174 }
michael@0 175
michael@0 176 STDMETHODIMP nsDataObjCollection::DUnadvise(DWORD dwConn)
michael@0 177 {
michael@0 178 return OLE_E_ADVISENOTSUPPORTED;
michael@0 179 }
michael@0 180
michael@0 181 STDMETHODIMP nsDataObjCollection::EnumDAdvise(LPENUMSTATDATA *ppEnum)
michael@0 182 {
michael@0 183 return OLE_E_ADVISENOTSUPPORTED;
michael@0 184 }
michael@0 185
michael@0 186 // GetData and SetData helper functions
michael@0 187 HRESULT nsDataObjCollection::AddSetFormat(FORMATETC& aFE)
michael@0 188 {
michael@0 189 return S_OK;
michael@0 190 }
michael@0 191
michael@0 192 HRESULT nsDataObjCollection::AddGetFormat(FORMATETC& aFE)
michael@0 193 {
michael@0 194 return S_OK;
michael@0 195 }
michael@0 196
michael@0 197 // Registers a DataFlavor/FE pair
michael@0 198 void nsDataObjCollection::AddDataFlavor(const char * aDataFlavor,
michael@0 199 LPFORMATETC aFE)
michael@0 200 {
michael@0 201 // Add the FormatEtc to our list if it's not already there. We don't care
michael@0 202 // about the internal aDataFlavor because nsDataObj handles that.
michael@0 203 IEnumFORMATETC * ifEtc;
michael@0 204 FORMATETC fEtc;
michael@0 205 ULONG num;
michael@0 206 if (S_OK != this->EnumFormatEtc(DATADIR_GET, &ifEtc))
michael@0 207 return;
michael@0 208 while (S_OK == ifEtc->Next(1, &fEtc, &num)) {
michael@0 209 NS_ASSERTION(1 == num,
michael@0 210 "Bit off more than we can chew in nsDataObjCollection::AddDataFlavor");
michael@0 211 if (FormatsMatch(fEtc, *aFE)) {
michael@0 212 ifEtc->Release();
michael@0 213 return;
michael@0 214 }
michael@0 215 } // If we didn't find a matching format, add this one
michael@0 216 ifEtc->Release();
michael@0 217 m_enumFE->AddFormatEtc(aFE);
michael@0 218 }
michael@0 219
michael@0 220 // We accept ownership of the nsDataObj which we free on destruction
michael@0 221 void nsDataObjCollection::AddDataObject(IDataObject * aDataObj)
michael@0 222 {
michael@0 223 nsDataObj* dataObj = reinterpret_cast<nsDataObj*>(aDataObj);
michael@0 224 mDataObjects.AppendElement(dataObj);
michael@0 225 }
michael@0 226
michael@0 227 // Methods for getting data
michael@0 228 HRESULT nsDataObjCollection::GetFile(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
michael@0 229 {
michael@0 230 STGMEDIUM workingmedium;
michael@0 231 FORMATETC fe = *pFE;
michael@0 232 HGLOBAL hGlobalMemory;
michael@0 233 HRESULT hr;
michael@0 234 // Make enough space for the header and the trailing null
michael@0 235 uint32_t buffersize = sizeof(DROPFILES) + sizeof(char16_t);
michael@0 236 uint32_t alloclen = 0;
michael@0 237 char16_t* realbuffer;
michael@0 238 nsAutoString filename;
michael@0 239
michael@0 240 hGlobalMemory = GlobalAlloc(GHND, buffersize);
michael@0 241
michael@0 242 for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
michael@0 243 nsDataObj* dataObj = mDataObjects.ElementAt(i);
michael@0 244 hr = dataObj->GetData(&fe, &workingmedium);
michael@0 245 if (hr != S_OK) {
michael@0 246 switch (hr) {
michael@0 247 case DV_E_FORMATETC:
michael@0 248 continue;
michael@0 249 default:
michael@0 250 return hr;
michael@0 251 }
michael@0 252 }
michael@0 253 // Now we need to pull out the filename
michael@0 254 char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal);
michael@0 255 if (buffer == nullptr)
michael@0 256 return E_FAIL;
michael@0 257 buffer += sizeof(DROPFILES)/sizeof(char16_t);
michael@0 258 filename = buffer;
michael@0 259 GlobalUnlock(workingmedium.hGlobal);
michael@0 260 ReleaseStgMedium(&workingmedium);
michael@0 261 // Now put the filename into our buffer
michael@0 262 alloclen = (filename.Length() + 1) * sizeof(char16_t);
michael@0 263 hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
michael@0 264 if (hGlobalMemory == nullptr)
michael@0 265 return E_FAIL;
michael@0 266 realbuffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize);
michael@0 267 if (!realbuffer)
michael@0 268 return E_FAIL;
michael@0 269 realbuffer--; // Overwrite the preceding null
michael@0 270 memcpy(realbuffer, filename.get(), alloclen);
michael@0 271 GlobalUnlock(hGlobalMemory);
michael@0 272 buffersize += alloclen;
michael@0 273 }
michael@0 274 // We get the last null (on the double null terminator) for free since we used
michael@0 275 // the zero memory flag when we allocated. All we need to do is fill the
michael@0 276 // DROPFILES structure
michael@0 277 DROPFILES* df = (DROPFILES*)GlobalLock(hGlobalMemory);
michael@0 278 if (!df)
michael@0 279 return E_FAIL;
michael@0 280 df->pFiles = sizeof(DROPFILES); //Offset to start of file name string
michael@0 281 df->fNC = 0;
michael@0 282 df->pt.x = 0;
michael@0 283 df->pt.y = 0;
michael@0 284 df->fWide = TRUE; // utf-16 chars
michael@0 285 GlobalUnlock(hGlobalMemory);
michael@0 286 // Finally fill out the STGMEDIUM struct
michael@0 287 pSTM->tymed = TYMED_HGLOBAL;
michael@0 288 pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
michael@0 289 pSTM->hGlobal = hGlobalMemory;
michael@0 290 return S_OK;
michael@0 291 }
michael@0 292
michael@0 293 HRESULT nsDataObjCollection::GetText(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
michael@0 294 {
michael@0 295 STGMEDIUM workingmedium;
michael@0 296 FORMATETC fe = *pFE;
michael@0 297 HGLOBAL hGlobalMemory;
michael@0 298 HRESULT hr;
michael@0 299 uint32_t buffersize = 1;
michael@0 300 uint32_t alloclen = 0;
michael@0 301
michael@0 302 hGlobalMemory = GlobalAlloc(GHND, buffersize);
michael@0 303
michael@0 304 if (pFE->cfFormat == CF_TEXT) {
michael@0 305 nsAutoCString text;
michael@0 306 for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
michael@0 307 nsDataObj* dataObj = mDataObjects.ElementAt(i);
michael@0 308 hr = dataObj->GetData(&fe, &workingmedium);
michael@0 309 if (hr != S_OK) {
michael@0 310 switch (hr) {
michael@0 311 case DV_E_FORMATETC:
michael@0 312 continue;
michael@0 313 default:
michael@0 314 return hr;
michael@0 315 }
michael@0 316 }
michael@0 317 // Now we need to pull out the text
michael@0 318 char* buffer = (char*)GlobalLock(workingmedium.hGlobal);
michael@0 319 if (buffer == nullptr)
michael@0 320 return E_FAIL;
michael@0 321 text = buffer;
michael@0 322 GlobalUnlock(workingmedium.hGlobal);
michael@0 323 ReleaseStgMedium(&workingmedium);
michael@0 324 // Now put the text into our buffer
michael@0 325 alloclen = text.Length();
michael@0 326 hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
michael@0 327 GHND);
michael@0 328 if (hGlobalMemory == nullptr)
michael@0 329 return E_FAIL;
michael@0 330 buffer = ((char*)GlobalLock(hGlobalMemory) + buffersize);
michael@0 331 if (!buffer)
michael@0 332 return E_FAIL;
michael@0 333 buffer--; // Overwrite the preceding null
michael@0 334 memcpy(buffer, text.get(), alloclen);
michael@0 335 GlobalUnlock(hGlobalMemory);
michael@0 336 buffersize += alloclen;
michael@0 337 }
michael@0 338 pSTM->tymed = TYMED_HGLOBAL;
michael@0 339 pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
michael@0 340 pSTM->hGlobal = hGlobalMemory;
michael@0 341 return S_OK;
michael@0 342 }
michael@0 343 if (pFE->cfFormat == CF_UNICODETEXT) {
michael@0 344 buffersize = sizeof(char16_t);
michael@0 345 nsAutoString text;
michael@0 346 for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
michael@0 347 nsDataObj* dataObj = mDataObjects.ElementAt(i);
michael@0 348 hr = dataObj->GetData(&fe, &workingmedium);
michael@0 349 if (hr != S_OK) {
michael@0 350 switch (hr) {
michael@0 351 case DV_E_FORMATETC:
michael@0 352 continue;
michael@0 353 default:
michael@0 354 return hr;
michael@0 355 }
michael@0 356 }
michael@0 357 // Now we need to pull out the text
michael@0 358 char16_t* buffer = (char16_t*)GlobalLock(workingmedium.hGlobal);
michael@0 359 if (buffer == nullptr)
michael@0 360 return E_FAIL;
michael@0 361 text = buffer;
michael@0 362 GlobalUnlock(workingmedium.hGlobal);
michael@0 363 ReleaseStgMedium(&workingmedium);
michael@0 364 // Now put the text into our buffer
michael@0 365 alloclen = text.Length() * sizeof(char16_t);
michael@0 366 hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen,
michael@0 367 GHND);
michael@0 368 if (hGlobalMemory == nullptr)
michael@0 369 return E_FAIL;
michael@0 370 buffer = (char16_t*)((char*)GlobalLock(hGlobalMemory) + buffersize);
michael@0 371 if (!buffer)
michael@0 372 return E_FAIL;
michael@0 373 buffer--; // Overwrite the preceding null
michael@0 374 memcpy(buffer, text.get(), alloclen);
michael@0 375 GlobalUnlock(hGlobalMemory);
michael@0 376 buffersize += alloclen;
michael@0 377 }
michael@0 378 pSTM->tymed = TYMED_HGLOBAL;
michael@0 379 pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
michael@0 380 pSTM->hGlobal = hGlobalMemory;
michael@0 381 return S_OK;
michael@0 382 }
michael@0 383
michael@0 384 return E_FAIL;
michael@0 385 }
michael@0 386
michael@0 387 HRESULT nsDataObjCollection::GetFileDescriptors(LPFORMATETC pFE,
michael@0 388 LPSTGMEDIUM pSTM)
michael@0 389 {
michael@0 390 STGMEDIUM workingmedium;
michael@0 391 FORMATETC fe = *pFE;
michael@0 392 HGLOBAL hGlobalMemory;
michael@0 393 HRESULT hr;
michael@0 394 uint32_t buffersize = sizeof(FILEGROUPDESCRIPTOR);
michael@0 395 uint32_t alloclen = sizeof(FILEDESCRIPTOR);
michael@0 396
michael@0 397 hGlobalMemory = GlobalAlloc(GHND, buffersize);
michael@0 398
michael@0 399 for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
michael@0 400 nsDataObj* dataObj = mDataObjects.ElementAt(i);
michael@0 401 hr = dataObj->GetData(&fe, &workingmedium);
michael@0 402 if (hr != S_OK) {
michael@0 403 switch (hr) {
michael@0 404 case DV_E_FORMATETC:
michael@0 405 continue;
michael@0 406 default:
michael@0 407 return hr;
michael@0 408 }
michael@0 409 }
michael@0 410 // Now we need to pull out the filedescriptor
michael@0 411 FILEDESCRIPTOR* buffer =
michael@0 412 (FILEDESCRIPTOR*)((char*)GlobalLock(workingmedium.hGlobal) + sizeof(UINT));
michael@0 413 if (buffer == nullptr)
michael@0 414 return E_FAIL;
michael@0 415 hGlobalMemory = ::GlobalReAlloc(hGlobalMemory, buffersize + alloclen, GHND);
michael@0 416 if (hGlobalMemory == nullptr)
michael@0 417 return E_FAIL;
michael@0 418 FILEGROUPDESCRIPTOR* realbuffer =
michael@0 419 (FILEGROUPDESCRIPTOR*)GlobalLock(hGlobalMemory);
michael@0 420 if (!realbuffer)
michael@0 421 return E_FAIL;
michael@0 422 FILEDESCRIPTOR* copyloc = (FILEDESCRIPTOR*)((char*)realbuffer + buffersize);
michael@0 423 memcpy(copyloc, buffer, sizeof(FILEDESCRIPTOR));
michael@0 424 realbuffer->cItems++;
michael@0 425 GlobalUnlock(hGlobalMemory);
michael@0 426 GlobalUnlock(workingmedium.hGlobal);
michael@0 427 ReleaseStgMedium(&workingmedium);
michael@0 428 buffersize += alloclen;
michael@0 429 }
michael@0 430 pSTM->tymed = TYMED_HGLOBAL;
michael@0 431 pSTM->pUnkForRelease = nullptr; // Caller gets to free the data
michael@0 432 pSTM->hGlobal = hGlobalMemory;
michael@0 433 return S_OK;
michael@0 434 }
michael@0 435
michael@0 436 HRESULT nsDataObjCollection::GetFileContents(LPFORMATETC pFE, LPSTGMEDIUM pSTM)
michael@0 437 {
michael@0 438 ULONG num = 0;
michael@0 439 ULONG numwanted = (pFE->lindex == -1) ? 0 : pFE->lindex;
michael@0 440 FORMATETC fEtc = *pFE;
michael@0 441 fEtc.lindex = -1; // We're lying to the data object so it thinks it's alone
michael@0 442
michael@0 443 // The key for this data type is to figure out which data object the index
michael@0 444 // corresponds to and then just pass it along
michael@0 445 for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
michael@0 446 nsDataObj* dataObj = mDataObjects.ElementAt(i);
michael@0 447 if (dataObj->QueryGetData(&fEtc) != S_OK)
michael@0 448 continue;
michael@0 449 if (num == numwanted)
michael@0 450 return dataObj->GetData(pFE, pSTM);
michael@0 451 numwanted++;
michael@0 452 }
michael@0 453 return DV_E_LINDEX;
michael@0 454 }
michael@0 455
michael@0 456 HRESULT nsDataObjCollection::GetFirstSupporting(LPFORMATETC pFE,
michael@0 457 LPSTGMEDIUM pSTM)
michael@0 458 {
michael@0 459 // There is no way to pass more than one of this, so just find the first data
michael@0 460 // object that supports it and pass it along
michael@0 461 for (uint32_t i = 0; i < mDataObjects.Length(); ++i) {
michael@0 462 if (mDataObjects.ElementAt(i)->QueryGetData(pFE) == S_OK)
michael@0 463 return mDataObjects.ElementAt(i)->GetData(pFE, pSTM);
michael@0 464 }
michael@0 465 return DV_E_FORMATETC;
michael@0 466 }

mercurial