os_exchange_data_provider_win.cc 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
  5. #include <coml2api.h>
  6. #include <objbase.h>
  7. #include <objidl.h>
  8. #include <shlobj.h>
  9. #include <shobjidl.h>
  10. #include <stdint.h>
  11. #include <wrl/client.h>
  12. #include <algorithm>
  13. #include <iterator>
  14. #include "base/callback.h"
  15. #include "base/check_op.h"
  16. #include "base/containers/span.h"
  17. #include "base/files/file_path.h"
  18. #include "base/i18n/file_util_icu.h"
  19. #include "base/no_destructor.h"
  20. #include "base/notreached.h"
  21. #include "base/pickle.h"
  22. #include "base/strings/string_util.h"
  23. #include "base/strings/utf_string_conversions.h"
  24. #include "base/win/scoped_hdc.h"
  25. #include "base/win/scoped_hglobal.h"
  26. #include "base/win/shlwapi.h"
  27. #include "net/base/filename_util.h"
  28. #include "skia/ext/skia_utils_win.h"
  29. #include "third_party/skia/include/core/SkBitmap.h"
  30. #include "ui/base/clipboard/clipboard_format_type.h"
  31. #include "ui/base/clipboard/clipboard_util_win.h"
  32. #include "ui/base/clipboard/file_info.h"
  33. #include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
  34. #include "ui/base/l10n/l10n_util.h"
  35. #include "ui/base/l10n/l10n_util_win.h"
  36. #include "ui/gfx/geometry/point.h"
  37. #include "ui/gfx/geometry/size.h"
  38. #include "ui/gfx/image/image_skia.h"
  39. #include "ui/gfx/skbitmap_operations.h"
  40. #include "ui/strings/grit/ui_strings.h"
  41. #include "url/gurl.h"
  42. namespace ui {
  43. namespace {
  44. constexpr STGMEDIUM kNullStorageMedium = {.tymed = TYMED_NULL,
  45. .pUnkForRelease = nullptr};
  46. // Creates a new STGMEDIUM object to hold the specified text. The caller
  47. // owns the resulting object. The "Bytes" version does not NULL terminate, the
  48. // string version does.
  49. STGMEDIUM CreateStorageForBytes(const void* data, size_t bytes);
  50. template <typename T>
  51. STGMEDIUM CreateStorageForString(const std::basic_string<T>& data);
  52. STGMEDIUM CreateIdListStorageForFileName(const base::FilePath& path);
  53. // Creates a File Descriptor for the creation of a file to the given URL and
  54. // returns a handle to it.
  55. STGMEDIUM CreateStorageForFileDescriptor(const base::FilePath& path);
  56. const ClipboardFormatType& GetRendererTaintFormatType();
  57. const ClipboardFormatType& GetFromPrivilegedFormatType();
  58. const ClipboardFormatType& GetIgnoreFileContentsFormatType();
  59. // Creates the contents of an Internet Shortcut file for the given URL.
  60. std::string GetInternetShortcutFileContents(const GURL& url);
  61. // Creates a valid file name given a suggested title and URL.
  62. std::wstring CreateValidFileNameFromTitle(const GURL& url,
  63. const std::wstring& title);
  64. } // namespace
  65. ///////////////////////////////////////////////////////////////////////////////
  66. // FormatEtcEnumerator
  67. //
  68. // This object implements an enumeration interface. The existence of an
  69. // implementation of this interface is exposed to clients through
  70. // OSExchangeData's EnumFormatEtc method. Our implementation is nobody's
  71. // business but our own, so it lives in this file.
  72. //
  73. // This Windows API is truly a gem. It wants to be an enumerator but assumes
  74. // some sort of sequential data (why not just use an array?). See comments
  75. // throughout.
  76. //
  77. class FormatEtcEnumerator final : public IEnumFORMATETC {
  78. public:
  79. FormatEtcEnumerator(DataObjectImpl::StoredData::const_iterator begin,
  80. DataObjectImpl::StoredData::const_iterator end);
  81. FormatEtcEnumerator(const FormatEtcEnumerator&) = delete;
  82. FormatEtcEnumerator& operator=(const FormatEtcEnumerator&) = delete;
  83. ~FormatEtcEnumerator();
  84. // IEnumFORMATETC implementation:
  85. HRESULT __stdcall Next(ULONG count,
  86. FORMATETC* elements_array,
  87. ULONG* elements_fetched) override;
  88. HRESULT __stdcall Skip(ULONG skip_count) override;
  89. HRESULT __stdcall Reset() override;
  90. HRESULT __stdcall Clone(IEnumFORMATETC** clone) override;
  91. // IUnknown implementation:
  92. HRESULT __stdcall QueryInterface(const IID& iid, void** object) override;
  93. ULONG __stdcall AddRef() override;
  94. ULONG __stdcall Release() override;
  95. private:
  96. // This can only be called from |CloneFromOther|, since it initializes the
  97. // contents_ from the other enumerator's contents.
  98. FormatEtcEnumerator() : cursor_(0), ref_count_(0) {
  99. }
  100. // Clone a new FormatEtc from another instance of this enumeration.
  101. static FormatEtcEnumerator* CloneFromOther(const FormatEtcEnumerator* other);
  102. private:
  103. // We are _forced_ to use a vector as our internal data model as Windows'
  104. // IEnumFORMATETC API assumes a deterministic ordering of elements through
  105. // methods like Next and Skip. This exposes the underlying data structure to
  106. // the user. Bah.
  107. std::vector<std::unique_ptr<FORMATETC>> contents_;
  108. // The cursor of the active enumeration - an index into |contents_|.
  109. size_t cursor_;
  110. ULONG ref_count_;
  111. };
  112. // Safely makes a copy of all of the relevant bits of a FORMATETC object.
  113. static void CloneFormatEtc(const FORMATETC* source, FORMATETC* clone) {
  114. *clone = *source;
  115. if (source->ptd) {
  116. clone->ptd =
  117. static_cast<DVTARGETDEVICE*>(CoTaskMemAlloc(sizeof(DVTARGETDEVICE)));
  118. *(clone->ptd) = *(source->ptd);
  119. }
  120. }
  121. FormatEtcEnumerator::FormatEtcEnumerator(
  122. DataObjectImpl::StoredData::const_iterator start,
  123. DataObjectImpl::StoredData::const_iterator end)
  124. : cursor_(0), ref_count_(0) {
  125. // Copy FORMATETC data from our source into ourselves.
  126. while (start != end) {
  127. auto format_etc = std::make_unique<FORMATETC>();
  128. CloneFormatEtc(&(*start)->format_etc, format_etc.get());
  129. contents_.push_back(std::move(format_etc));
  130. ++start;
  131. }
  132. }
  133. FormatEtcEnumerator::~FormatEtcEnumerator() {
  134. }
  135. HRESULT FormatEtcEnumerator::Next(ULONG count,
  136. FORMATETC* elements_array,
  137. ULONG* elements_fetched) {
  138. // MSDN says |elements_fetched| is allowed to be NULL if count is 1.
  139. if (!elements_fetched)
  140. DCHECK_EQ(count, 1ul);
  141. // This method copies count elements into |elements_array|.
  142. ULONG index = 0;
  143. while (cursor_ < contents_.size() && index < count) {
  144. CloneFormatEtc(contents_[cursor_].get(), &elements_array[index]);
  145. ++cursor_;
  146. ++index;
  147. }
  148. // The out param is for how many we actually copied.
  149. if (elements_fetched)
  150. *elements_fetched = index;
  151. // If the two don't agree, then we fail.
  152. return index == count ? S_OK : S_FALSE;
  153. }
  154. HRESULT FormatEtcEnumerator::Skip(ULONG skip_count) {
  155. cursor_ += skip_count;
  156. // MSDN implies it's OK to leave the enumerator trashed.
  157. // "Whatever you say, boss"
  158. return cursor_ <= contents_.size() ? S_OK : S_FALSE;
  159. }
  160. HRESULT FormatEtcEnumerator::Reset() {
  161. cursor_ = 0;
  162. return S_OK;
  163. }
  164. HRESULT FormatEtcEnumerator::Clone(IEnumFORMATETC** clone) {
  165. // Clone the current enumerator in its exact state, including cursor.
  166. FormatEtcEnumerator* e = CloneFromOther(this);
  167. e->AddRef();
  168. *clone = e;
  169. return S_OK;
  170. }
  171. HRESULT FormatEtcEnumerator::QueryInterface(const IID& iid, void** object) {
  172. *object = NULL;
  173. if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IEnumFORMATETC)) {
  174. *object = this;
  175. } else {
  176. return E_NOINTERFACE;
  177. }
  178. AddRef();
  179. return S_OK;
  180. }
  181. ULONG FormatEtcEnumerator::AddRef() {
  182. return InterlockedIncrement(&ref_count_);
  183. }
  184. ULONG FormatEtcEnumerator::Release() {
  185. if (InterlockedDecrement(&ref_count_) == 0) {
  186. ULONG copied_refcnt = ref_count_;
  187. delete this;
  188. return copied_refcnt;
  189. }
  190. return ref_count_;
  191. }
  192. // static
  193. FormatEtcEnumerator* FormatEtcEnumerator::CloneFromOther(
  194. const FormatEtcEnumerator* other) {
  195. FormatEtcEnumerator* e = new FormatEtcEnumerator;
  196. // Copy FORMATETC data from our source into ourselves.
  197. std::transform(other->contents_.cbegin(), other->contents_.cend(),
  198. std::back_inserter(e->contents_),
  199. [](const std::unique_ptr<FORMATETC>& format_etc) {
  200. auto clone = std::make_unique<FORMATETC>();
  201. CloneFormatEtc(format_etc.get(), clone.get());
  202. return clone;
  203. });
  204. // Carry over
  205. e->cursor_ = other->cursor_;
  206. return e;
  207. }
  208. ///////////////////////////////////////////////////////////////////////////////
  209. // OSExchangeDataProviderWin, public:
  210. // static
  211. bool OSExchangeDataProviderWin::HasPlainTextURL(IDataObject* source) {
  212. std::u16string plain_text;
  213. return (ClipboardUtil::GetPlainText(source, &plain_text) &&
  214. !plain_text.empty() && GURL(plain_text).is_valid());
  215. }
  216. // static
  217. bool OSExchangeDataProviderWin::GetPlainTextURL(IDataObject* source,
  218. GURL* url) {
  219. std::u16string plain_text;
  220. if (ClipboardUtil::GetPlainText(source, &plain_text) &&
  221. !plain_text.empty()) {
  222. GURL gurl(plain_text);
  223. if (gurl.is_valid()) {
  224. *url = gurl;
  225. return true;
  226. }
  227. }
  228. return false;
  229. }
  230. // static
  231. DataObjectImpl* OSExchangeDataProviderWin::GetDataObjectImpl(
  232. const OSExchangeData& data) {
  233. return static_cast<const OSExchangeDataProviderWin*>(&data.provider())->
  234. data_.get();
  235. }
  236. // static
  237. IDataObject* OSExchangeDataProviderWin::GetIDataObject(
  238. const OSExchangeData& data) {
  239. return static_cast<const OSExchangeDataProviderWin*>(&data.provider())->
  240. data_object();
  241. }
  242. OSExchangeDataProviderWin::OSExchangeDataProviderWin(IDataObject* source)
  243. : data_(new DataObjectImpl()),
  244. source_object_(source) {
  245. }
  246. OSExchangeDataProviderWin::OSExchangeDataProviderWin()
  247. : data_(new DataObjectImpl()),
  248. source_object_(data_.get()) {
  249. }
  250. OSExchangeDataProviderWin::~OSExchangeDataProviderWin() {
  251. }
  252. std::unique_ptr<OSExchangeDataProvider> OSExchangeDataProviderWin::Clone()
  253. const {
  254. return std::make_unique<OSExchangeDataProviderWin>(data_object());
  255. }
  256. void OSExchangeDataProviderWin::MarkOriginatedFromRenderer() {
  257. STGMEDIUM storage = CreateStorageForString(std::string());
  258. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  259. GetRendererTaintFormatType().ToFormatEtc(), storage));
  260. }
  261. bool OSExchangeDataProviderWin::DidOriginateFromRenderer() const {
  262. return HasCustomFormat(GetRendererTaintFormatType());
  263. }
  264. void OSExchangeDataProviderWin::MarkAsFromPrivileged() {
  265. STGMEDIUM storage = CreateStorageForString(std::string());
  266. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  267. GetFromPrivilegedFormatType().ToFormatEtc(), storage));
  268. }
  269. bool OSExchangeDataProviderWin::IsFromPrivileged() const {
  270. return HasCustomFormat(GetFromPrivilegedFormatType());
  271. }
  272. void OSExchangeDataProviderWin::SetString(const std::u16string& data) {
  273. STGMEDIUM storage = CreateStorageForString(data);
  274. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  275. ClipboardFormatType::PlainTextType().ToFormatEtc(), storage));
  276. // Also add the UTF8-encoded version.
  277. storage = CreateStorageForString(base::UTF16ToUTF8(data));
  278. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  279. ClipboardFormatType::PlainTextAType().ToFormatEtc(), storage));
  280. }
  281. void OSExchangeDataProviderWin::SetURL(const GURL& url,
  282. const std::u16string& title) {
  283. // NOTE WELL:
  284. // Every time you change the order of the first two CLIPFORMATS that get
  285. // added here, you need to update the EnumerationViaCOM test case in
  286. // the _unittest.cc file to reflect the new arrangement otherwise that test
  287. // will fail! It assumes an insertion order.
  288. // Add text/x-moz-url for drags from Firefox
  289. std::u16string x_moz_url_str = base::UTF8ToUTF16(url.spec());
  290. x_moz_url_str += '\n';
  291. x_moz_url_str += title;
  292. STGMEDIUM storage = CreateStorageForString(x_moz_url_str);
  293. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  294. ClipboardFormatType::MozUrlType().ToFormatEtc(), storage));
  295. // Add a .URL shortcut file for dragging to Explorer if there is not already
  296. // FileContents from dragging an image. Also mark the synthesized file
  297. // contents to be ignored if the drag ends up targeting Chrome. Otherwise,
  298. // this may confuse some web pages into dropping a file rather than a link.
  299. // See https://crbug.com/1274395 for background.
  300. if (!HasFileContents()) {
  301. std::wstring valid_file_name =
  302. CreateValidFileNameFromTitle(url, base::AsWString(title));
  303. std::string shortcut_url_file_contents =
  304. GetInternetShortcutFileContents(url);
  305. SetFileContents(base::FilePath(valid_file_name),
  306. shortcut_url_file_contents);
  307. STGMEDIUM storage = CreateStorageForString(std::string());
  308. data_->contents_.push_back(
  309. DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  310. GetIgnoreFileContentsFormatType().ToFormatEtc(), storage));
  311. }
  312. // Add a UniformResourceLocator link for apps like IE and Word.
  313. storage = CreateStorageForString(base::UTF8ToUTF16(url.spec()));
  314. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  315. ClipboardFormatType::UrlType().ToFormatEtc(), storage));
  316. storage = CreateStorageForString(url.spec());
  317. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  318. ClipboardFormatType::UrlAType().ToFormatEtc(), storage));
  319. // TODO(https://crbug.com/6767): add CF_HTML.
  320. // Also add text representations (these should be last since they're the
  321. // least preferable).
  322. SetString(base::UTF8ToUTF16(url.spec()));
  323. }
  324. void OSExchangeDataProviderWin::SetFilename(const base::FilePath& path) {
  325. SetFilenames({FileInfo(path, base::FilePath())});
  326. STGMEDIUM storage = CreateIdListStorageForFileName(path);
  327. if (storage.tymed == TYMED_NULL)
  328. return;
  329. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  330. ClipboardFormatType::IDListType().ToFormatEtc(), storage));
  331. }
  332. void OSExchangeDataProviderWin::SetFilenames(
  333. const std::vector<FileInfo>& filenames) {
  334. STGMEDIUM storage = ClipboardUtil::CreateStorageForFileNames(filenames);
  335. if (storage.tymed == TYMED_NULL)
  336. return;
  337. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  338. ClipboardFormatType::CFHDropType().ToFormatEtc(), storage));
  339. }
  340. void OSExchangeDataProviderWin::SetVirtualFileContentsForTesting(
  341. const std::vector<std::pair<base::FilePath, std::string>>&
  342. filenames_and_contents,
  343. DWORD tymed) {
  344. size_t num_files = filenames_and_contents.size();
  345. if (!num_files)
  346. return;
  347. // Allocate storage for the file group descriptor as CFSTR_FILEDESCRIPTORW.
  348. // The fgd[] member of FILEGROUPDESCRIPTORW is of size one, thus sizeof
  349. // (FILEDESCRIPTORW) is already the correct allocation size if there is only
  350. // one item. Otherwise need to add room for each FILEDESCRIPTORW struct.
  351. const size_t total_bytes_fgd = sizeof(FILEGROUPDESCRIPTORW) +
  352. (sizeof(FILEDESCRIPTORW) * (num_files - 1));
  353. HANDLE hdata = ::GlobalAlloc(GPTR, total_bytes_fgd);
  354. if (!hdata)
  355. return;
  356. base::win::ScopedHGlobal<FILEGROUPDESCRIPTORW*> locked_mem(hdata);
  357. FILEGROUPDESCRIPTORW* descriptor = locked_mem.get();
  358. descriptor->cItems = base::checked_cast<UINT>(num_files);
  359. STGMEDIUM storage = {
  360. .tymed = TYMED_HGLOBAL, .hGlobal = hdata, .pUnkForRelease = nullptr};
  361. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  362. ClipboardFormatType::FileDescriptorType().ToFormatEtc(), storage));
  363. for (size_t i = 0; i < num_files; i++) {
  364. // Fill in each FILEDESCRIPTORW with file name.
  365. descriptor->fgd[i].dwFlags |= static_cast<DWORD>(FD_UNICODE);
  366. std::wstring file_name = filenames_and_contents[i].first.value();
  367. wcsncpy_s(descriptor->fgd[i].cFileName, MAX_PATH, file_name.c_str(),
  368. std::min(file_name.size(), static_cast<size_t>(MAX_PATH - 1u)));
  369. // Add the contents of each file as CFSTR_FILECONTENTS.
  370. base::span<const uint8_t> data_buffer =
  371. base::make_span(reinterpret_cast<const uint8_t*>(
  372. filenames_and_contents[i].second.data()),
  373. filenames_and_contents[i].second.length());
  374. SetVirtualFileContentAtIndexForTesting(data_buffer, tymed, // IN-TEST
  375. static_cast<LONG>(i));
  376. }
  377. }
  378. void OSExchangeDataProviderWin::SetVirtualFileContentAtIndexForTesting(
  379. base::span<const uint8_t> data_buffer,
  380. DWORD tymed,
  381. LONG index) {
  382. STGMEDIUM storage_for_contents = kNullStorageMedium;
  383. if (tymed == TYMED_ISTORAGE) {
  384. Microsoft::WRL::ComPtr<ILockBytes> lock_bytes;
  385. HRESULT hr = ::CreateILockBytesOnHGlobal(
  386. nullptr, /* fDeleteOnRelease*/ TRUE, &lock_bytes);
  387. if (SUCCEEDED(hr)) {
  388. hr = ::StgCreateDocfileOnILockBytes(
  389. lock_bytes.Get(), STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  390. 0, &storage_for_contents.pstg);
  391. }
  392. Microsoft::WRL::ComPtr<IStream> destination_stream;
  393. if (SUCCEEDED(hr)) {
  394. hr = storage_for_contents.pstg->CreateStream(
  395. L"Contents", STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 0,
  396. 0, &destination_stream);
  397. }
  398. Microsoft::WRL::ComPtr<IStream> source_stream;
  399. if (SUCCEEDED(hr)) {
  400. source_stream = ::SHCreateMemStream(
  401. data_buffer.data(),
  402. base::checked_cast<UINT>(data_buffer.size_bytes()));
  403. }
  404. if (source_stream) {
  405. // Copy the data to the storage stream.
  406. ULARGE_INTEGER bytes_to_copy;
  407. bytes_to_copy.QuadPart = data_buffer.size_bytes();
  408. hr = source_stream->CopyTo(destination_stream.Get(), bytes_to_copy,
  409. nullptr, nullptr);
  410. }
  411. if (SUCCEEDED(hr))
  412. hr = storage_for_contents.pstg->Commit(STGC_DEFAULT);
  413. if (SUCCEEDED(hr))
  414. storage_for_contents.tymed = TYMED_ISTORAGE;
  415. } else if (tymed == TYMED_ISTREAM) {
  416. storage_for_contents.pstm = ::SHCreateMemStream(
  417. data_buffer.data(), base::checked_cast<UINT>(data_buffer.size_bytes()));
  418. if (storage_for_contents.pstm) {
  419. // A properly implemented IDataObject::GetData moves the stream pointer
  420. // to end.
  421. const LARGE_INTEGER kZeroDisplacement = {};
  422. HRESULT hr = storage_for_contents.pstm->Seek(kZeroDisplacement,
  423. STREAM_SEEK_END, nullptr);
  424. if (SUCCEEDED(hr))
  425. storage_for_contents.tymed = TYMED_ISTREAM;
  426. }
  427. } else if (tymed == TYMED_HGLOBAL) {
  428. storage_for_contents =
  429. CreateStorageForBytes(data_buffer.data(), data_buffer.size_bytes());
  430. }
  431. ClipboardFormatType type = ClipboardFormatType::FileContentAtIndexType(index);
  432. // Pass ownership of |storage_for_contents| here.
  433. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  434. type.ToFormatEtc(), storage_for_contents));
  435. }
  436. void OSExchangeDataProviderWin::SetPickledData(
  437. const ClipboardFormatType& format,
  438. const base::Pickle& data) {
  439. STGMEDIUM storage = CreateStorageForBytes(data.data(), data.size());
  440. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  441. format.ToFormatEtc(), storage));
  442. }
  443. void OSExchangeDataProviderWin::SetFileContents(
  444. const base::FilePath& filename,
  445. const std::string& file_contents) {
  446. // Add CFSTR_FILEDESCRIPTORW.
  447. STGMEDIUM storage = CreateStorageForFileDescriptor(filename);
  448. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  449. ClipboardFormatType::FileDescriptorType().ToFormatEtc(), storage));
  450. // Add CFSTR_FILECONTENTS.
  451. STGMEDIUM storage_contents =
  452. CreateStorageForBytes(file_contents.data(), file_contents.length());
  453. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  454. ClipboardFormatType::FileContentZeroType().ToFormatEtc(),
  455. storage_contents));
  456. }
  457. void OSExchangeDataProviderWin::SetHtml(const std::u16string& html,
  458. const GURL& base_url) {
  459. // Add both MS CF_HTML and text/html format. CF_HTML should be in utf-8.
  460. std::string utf8_html = base::UTF16ToUTF8(html);
  461. std::string url = base_url.is_valid() ? base_url.spec() : std::string();
  462. std::string cf_html = ClipboardUtil::HtmlToCFHtml(utf8_html, url);
  463. STGMEDIUM storage = CreateStorageForBytes(cf_html.c_str(), cf_html.size());
  464. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  465. ClipboardFormatType::HtmlType().ToFormatEtc(), storage));
  466. STGMEDIUM storage_plain =
  467. CreateStorageForBytes(utf8_html.c_str(), utf8_html.size());
  468. data_->contents_.push_back(DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  469. ClipboardFormatType::TextHtmlType().ToFormatEtc(), storage_plain));
  470. }
  471. bool OSExchangeDataProviderWin::GetString(std::u16string* data) const {
  472. return ClipboardUtil::GetPlainText(source_object_.Get(), data);
  473. }
  474. bool OSExchangeDataProviderWin::GetURLAndTitle(FilenameToURLPolicy policy,
  475. GURL* url,
  476. std::u16string* title) const {
  477. std::u16string url_str;
  478. bool success = ClipboardUtil::GetUrl(
  479. source_object_.Get(), url, title,
  480. policy == FilenameToURLPolicy::CONVERT_FILENAMES ? true : false);
  481. if (success) {
  482. DCHECK(url->is_valid());
  483. return true;
  484. } else if (GetPlainTextURL(source_object_.Get(), url)) {
  485. if (url->is_valid())
  486. *title = net::GetSuggestedFilename(*url, "", "", "", "", std::string());
  487. else
  488. title->clear();
  489. return true;
  490. }
  491. return false;
  492. }
  493. bool OSExchangeDataProviderWin::GetFilename(base::FilePath* path) const {
  494. std::vector<std::wstring> filenames;
  495. bool success = ClipboardUtil::GetFilenames(source_object_.Get(), &filenames);
  496. if (success)
  497. *path = base::FilePath(filenames[0]);
  498. return success;
  499. }
  500. bool OSExchangeDataProviderWin::GetFilenames(
  501. std::vector<FileInfo>* filenames) const {
  502. std::vector<std::wstring> filenames_local;
  503. bool success =
  504. ClipboardUtil::GetFilenames(source_object_.Get(), &filenames_local);
  505. if (success) {
  506. for (const std::wstring& filename_local : filenames_local)
  507. filenames->push_back(
  508. FileInfo(base::FilePath(filename_local), base::FilePath()));
  509. }
  510. return success;
  511. }
  512. bool OSExchangeDataProviderWin::HasVirtualFilenames() const {
  513. return ClipboardUtil::HasVirtualFilenames(source_object_.Get());
  514. }
  515. bool OSExchangeDataProviderWin::GetVirtualFilenames(
  516. std::vector<FileInfo>* filenames) const {
  517. // ui_base_clipboard can't use FileInfo struct which is part of ui_base, so
  518. // use FilePath instead.
  519. // TODO(https://crbug.com/950360): ui_base_clipboard can't use FileInfo struct
  520. // which is part of ui_base (layering issue).
  521. std::vector<base::FilePath> display_names;
  522. bool success =
  523. ClipboardUtil::GetVirtualFilenames(source_object_.Get(), &display_names);
  524. if (success) {
  525. // On dragenter scenarios, need a placeholder file path for drag metadata
  526. // checks without actually creating the temp file.
  527. base::FilePath temp_path(FILE_PATH_LITERAL("temp.tmp"));
  528. for (const auto& display_name : display_names)
  529. filenames->push_back(FileInfo(temp_path, display_name));
  530. }
  531. return success;
  532. }
  533. bool OSExchangeDataProviderWin::GetVirtualFilesAsTempFiles(
  534. base::OnceCallback<
  535. void(const std::vector<std::pair<base::FilePath, base::FilePath>>&)>
  536. callback) const {
  537. return ClipboardUtil::GetVirtualFilesAsTempFiles(source_object_.Get(),
  538. std::move(callback));
  539. }
  540. bool OSExchangeDataProviderWin::GetPickledData(
  541. const ClipboardFormatType& format,
  542. base::Pickle* data) const {
  543. DCHECK(data);
  544. bool success = false;
  545. STGMEDIUM medium;
  546. FORMATETC format_etc = format.ToFormatEtc();
  547. if (SUCCEEDED(source_object_->GetData(&format_etc, &medium))) {
  548. if (medium.tymed & TYMED_HGLOBAL) {
  549. base::win::ScopedHGlobal<char*> c_data(medium.hGlobal);
  550. DCHECK_GT(c_data.Size(), 0u);
  551. *data = base::Pickle(c_data.get(), c_data.Size());
  552. success = true;
  553. }
  554. ReleaseStgMedium(&medium);
  555. }
  556. return success;
  557. }
  558. bool OSExchangeDataProviderWin::GetFileContents(
  559. base::FilePath* filename,
  560. std::string* file_contents) const {
  561. if (HasCustomFormat(GetIgnoreFileContentsFormatType()))
  562. return false;
  563. std::wstring filename_str;
  564. if (!ClipboardUtil::GetFileContents(source_object_.Get(), &filename_str,
  565. file_contents)) {
  566. return false;
  567. }
  568. *filename = base::FilePath(filename_str);
  569. return true;
  570. }
  571. bool OSExchangeDataProviderWin::GetHtml(std::u16string* html,
  572. GURL* base_url) const {
  573. std::string url;
  574. bool success = ClipboardUtil::GetHtml(source_object_.Get(), html, &url);
  575. if (success)
  576. *base_url = GURL(url);
  577. return success;
  578. }
  579. bool OSExchangeDataProviderWin::HasString() const {
  580. return ClipboardUtil::HasPlainText(source_object_.Get());
  581. }
  582. bool OSExchangeDataProviderWin::HasURL(FilenameToURLPolicy policy) const {
  583. return (ClipboardUtil::HasUrl(source_object_.Get(),
  584. policy == FilenameToURLPolicy::CONVERT_FILENAMES
  585. ? true
  586. : false) ||
  587. HasPlainTextURL(source_object_.Get()));
  588. }
  589. bool OSExchangeDataProviderWin::HasFile() const {
  590. return ClipboardUtil::HasFilenames(source_object_.Get());
  591. }
  592. bool OSExchangeDataProviderWin::HasFileContents() const {
  593. return ClipboardUtil::HasFileContents(source_object_.Get()) &&
  594. !HasCustomFormat(GetIgnoreFileContentsFormatType());
  595. }
  596. bool OSExchangeDataProviderWin::HasHtml() const {
  597. return ClipboardUtil::HasHtml(source_object_.Get());
  598. }
  599. bool OSExchangeDataProviderWin::HasCustomFormat(
  600. const ClipboardFormatType& format) const {
  601. FORMATETC format_etc = format.ToFormatEtc();
  602. return (source_object_->QueryGetData(&format_etc) == S_OK);
  603. }
  604. void OSExchangeDataProviderWin::SetDownloadFileInfo(
  605. DownloadFileInfo* download) {
  606. // If the filename is not provided, set storage to NULL to indicate that
  607. // the delay rendering will be used.
  608. // TODO(dcheng): Is it actually possible for filename to be empty here? I
  609. // think we always synthesize one in WebContentsDragWin.
  610. STGMEDIUM storage = kNullStorageMedium;
  611. if (!download->filename.empty()) {
  612. ClipboardUtil::CreateStorageForFileNames(
  613. {FileInfo(download->filename, base::FilePath())});
  614. }
  615. // Add CF_HDROP.
  616. auto info = DataObjectImpl::StoredDataInfo::TakeStorageMedium(
  617. ClipboardFormatType::CFHDropType().ToFormatEtc(), storage);
  618. info->downloader = std::move(download->downloader);
  619. data_->contents_.push_back(std::move(info));
  620. // Adding a download file always enables async mode.
  621. data_->SetAsyncMode(VARIANT_TRUE);
  622. }
  623. void OSExchangeDataProviderWin::SetDragImage(
  624. const gfx::ImageSkia& image_skia,
  625. const gfx::Vector2d& cursor_offset) {
  626. DCHECK(!image_skia.size().IsEmpty());
  627. // InitializeFromBitmap() doesn't expect an alpha channel and is confused
  628. // by premultiplied colors, so unpremultiply the bitmap.
  629. SkBitmap unpremul_bitmap =
  630. SkBitmapOperations::UnPreMultiply(*image_skia.bitmap());
  631. Microsoft::WRL::ComPtr<IDragSourceHelper> helper;
  632. HRESULT rv = CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER,
  633. IID_PPV_ARGS(&helper));
  634. if (!SUCCEEDED(rv))
  635. return;
  636. base::win::ScopedBitmap hbitmap =
  637. skia::CreateHBitmapFromN32SkBitmap(unpremul_bitmap);
  638. if (!hbitmap.is_valid())
  639. return;
  640. // InitializeFromBitmap() takes ownership of |hbitmap|.
  641. SHDRAGIMAGE sdi;
  642. sdi.sizeDragImage.cx = unpremul_bitmap.width();
  643. sdi.sizeDragImage.cy = unpremul_bitmap.height();
  644. sdi.crColorKey = 0xFFFFFFFF;
  645. sdi.hbmpDragImage = hbitmap.release();
  646. sdi.ptOffset = gfx::PointAtOffsetFromOrigin(cursor_offset).ToPOINT();
  647. helper->InitializeFromBitmap(&sdi, data_object());
  648. }
  649. gfx::ImageSkia OSExchangeDataProviderWin::GetDragImage() const {
  650. // This class sets the image on data_object() so it shouldn't be used in
  651. // situations where the drag image is later queried. In that case a different
  652. // OSExchangeDataProvider should be used.
  653. NOTREACHED();
  654. return gfx::ImageSkia();
  655. }
  656. gfx::Vector2d OSExchangeDataProviderWin::GetDragImageOffset() const {
  657. // This class sets the image on data_object() so it shouldn't be used in
  658. // situations where the drag image is later queried. In that case a different
  659. // OSExchangeDataProvider should be used.
  660. NOTREACHED();
  661. return gfx::Vector2d();
  662. }
  663. void OSExchangeDataProviderWin::SetSource(
  664. std::unique_ptr<DataTransferEndpoint> data_source) {}
  665. DataTransferEndpoint* OSExchangeDataProviderWin::GetSource() const {
  666. return nullptr;
  667. }
  668. ///////////////////////////////////////////////////////////////////////////////
  669. // DataObjectImpl, IDataObject implementation:
  670. // The following function, DuplicateMedium, is derived from WCDataObject.cpp
  671. // in the WebKit source code. This is the license information for the file:
  672. /*
  673. * Copyright (C) 2007 Apple Inc. All rights reserved.
  674. *
  675. * Redistribution and use in source and binary forms, with or without
  676. * modification, are permitted provided that the following conditions
  677. * are met:
  678. * 1. Redistributions of source code must retain the above copyright
  679. * notice, this list of conditions and the following disclaimer.
  680. * 2. Redistributions in binary form must reproduce the above copyright
  681. * notice, this list of conditions and the following disclaimer in the
  682. * documentation and/or other materials provided with the distribution.
  683. *
  684. * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  685. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  686. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  687. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  688. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  689. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  690. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  691. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  692. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  693. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  694. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  695. */
  696. static STGMEDIUM DuplicateMedium(CLIPFORMAT clipformat,
  697. const STGMEDIUM& storage) {
  698. STGMEDIUM copied = kNullStorageMedium;
  699. switch (storage.tymed) {
  700. case TYMED_HGLOBAL:
  701. copied.hGlobal = static_cast<HGLOBAL>(
  702. OleDuplicateData(storage.hGlobal, clipformat, 0));
  703. break;
  704. case TYMED_MFPICT:
  705. copied.hMetaFilePict = static_cast<HMETAFILEPICT>(
  706. OleDuplicateData(storage.hMetaFilePict, clipformat, 0));
  707. break;
  708. case TYMED_GDI:
  709. copied.hBitmap = static_cast<HBITMAP>(
  710. OleDuplicateData(storage.hBitmap, clipformat, 0));
  711. break;
  712. case TYMED_ENHMF:
  713. copied.hEnhMetaFile = static_cast<HENHMETAFILE>(
  714. OleDuplicateData(storage.hEnhMetaFile, clipformat, 0));
  715. break;
  716. case TYMED_FILE:
  717. copied.lpszFileName = static_cast<LPOLESTR>(
  718. OleDuplicateData(storage.lpszFileName, clipformat, 0));
  719. break;
  720. case TYMED_ISTREAM:
  721. copied.pstm = storage.pstm;
  722. copied.pstm->AddRef();
  723. break;
  724. case TYMED_ISTORAGE:
  725. copied.pstg = storage.pstg;
  726. copied.pstg->AddRef();
  727. break;
  728. }
  729. copied.tymed = storage.tymed;
  730. copied.pUnkForRelease = storage.pUnkForRelease;
  731. if (copied.pUnkForRelease)
  732. copied.pUnkForRelease->AddRef();
  733. return copied;
  734. }
  735. DataObjectImpl::StoredDataInfo::~StoredDataInfo() {
  736. ReleaseStgMedium(&medium);
  737. if (downloader.get())
  738. downloader->Stop();
  739. }
  740. // Takes ownership of and nullifies `medium`.
  741. std::unique_ptr<DataObjectImpl::StoredDataInfo>
  742. DataObjectImpl::StoredDataInfo::TakeStorageMedium(const FORMATETC& format_etc,
  743. STGMEDIUM& medium) {
  744. std::unique_ptr<StoredDataInfo> info(new StoredDataInfo(format_etc, medium));
  745. // Null `medium` out.
  746. medium = kNullStorageMedium;
  747. return info;
  748. }
  749. DataObjectImpl::StoredDataInfo::StoredDataInfo(const FORMATETC& format_etc,
  750. const STGMEDIUM& medium)
  751. : format_etc(format_etc), medium(medium) {}
  752. DataObjectImpl::DataObjectImpl()
  753. : is_aborting_(false),
  754. in_drag_loop_(false),
  755. in_async_mode_(false),
  756. async_operation_started_(false) {}
  757. DataObjectImpl::~DataObjectImpl() {
  758. StopDownloads();
  759. }
  760. void DataObjectImpl::StopDownloads() {
  761. for (const std::unique_ptr<StoredDataInfo>& content : contents_) {
  762. if (content->downloader.get()) {
  763. content->downloader->Stop();
  764. content->downloader = 0;
  765. }
  766. }
  767. }
  768. void DataObjectImpl::RemoveData(const FORMATETC& format) {
  769. if (format.ptd)
  770. return; // Don't attempt to compare target devices.
  771. for (StoredData::iterator i = contents_.begin(); i != contents_.end(); ++i) {
  772. if (!(*i)->format_etc.ptd &&
  773. format.cfFormat == (*i)->format_etc.cfFormat &&
  774. format.dwAspect == (*i)->format_etc.dwAspect &&
  775. format.lindex == (*i)->format_etc.lindex &&
  776. format.tymed == (*i)->format_etc.tymed) {
  777. contents_.erase(i);
  778. return;
  779. }
  780. }
  781. }
  782. void DataObjectImpl::OnDownloadCompleted(const base::FilePath& file_path) {
  783. for (std::unique_ptr<StoredDataInfo>& content : contents_) {
  784. if (content->format_etc.cfFormat == CF_HDROP) {
  785. // Retrieve the downloader first so it won't get destroyed.
  786. auto downloader = std::move(content->downloader);
  787. if (downloader)
  788. downloader->Stop();
  789. // Replace stored data.
  790. STGMEDIUM storage = ClipboardUtil::CreateStorageForFileNames(
  791. {FileInfo(file_path, base::FilePath())});
  792. content = StoredDataInfo::TakeStorageMedium(
  793. ClipboardFormatType::CFHDropType().ToFormatEtc(), storage);
  794. content->downloader = std::move(downloader);
  795. break;
  796. }
  797. }
  798. }
  799. void DataObjectImpl::OnDownloadAborted() {}
  800. HRESULT DataObjectImpl::GetData(FORMATETC* format_etc, STGMEDIUM* medium) {
  801. if (is_aborting_)
  802. return DV_E_FORMATETC;
  803. for (const std::unique_ptr<StoredDataInfo>& content : contents_) {
  804. if (content->format_etc.cfFormat == format_etc->cfFormat &&
  805. content->format_etc.lindex == format_etc->lindex &&
  806. (content->format_etc.tymed & format_etc->tymed)) {
  807. // If medium is NULL, delay-rendering will be used.
  808. if (content->medium.tymed != TYMED_NULL) {
  809. *medium =
  810. DuplicateMedium(content->format_etc.cfFormat, content->medium);
  811. return S_OK;
  812. }
  813. // Fail all GetData() attempts for DownloadURL data if the drag and drop
  814. // operation is still in progress.
  815. if (in_drag_loop_)
  816. return DV_E_FORMATETC;
  817. bool wait_for_data = false;
  818. // In async mode, we do not want to start waiting for the data before
  819. // the async operation is started. This is because we want to postpone
  820. // until Shell kicks off a background thread to do the work so that
  821. // we do not block the UI thread.
  822. if (!in_async_mode_ || async_operation_started_)
  823. wait_for_data = true;
  824. if (!wait_for_data)
  825. return DV_E_FORMATETC;
  826. // Now we can start the download.
  827. if (content->downloader.get()) {
  828. content->downloader->Start(this);
  829. if (!content->downloader->Wait()) {
  830. is_aborting_ = true;
  831. return DV_E_FORMATETC;
  832. }
  833. }
  834. // The stored data should have been updated with the final version.
  835. // So we just need to call this function again to retrieve it.
  836. return GetData(format_etc, medium);
  837. }
  838. }
  839. return DV_E_FORMATETC;
  840. }
  841. HRESULT DataObjectImpl::GetDataHere(FORMATETC* format_etc,
  842. STGMEDIUM* medium) {
  843. return DATA_E_FORMATETC;
  844. }
  845. HRESULT DataObjectImpl::QueryGetData(FORMATETC* format_etc) {
  846. for (const std::unique_ptr<StoredDataInfo>& content : contents_) {
  847. if (content->format_etc.cfFormat == format_etc->cfFormat)
  848. return S_OK;
  849. }
  850. return DV_E_FORMATETC;
  851. }
  852. HRESULT DataObjectImpl::GetCanonicalFormatEtc(
  853. FORMATETC* format_etc, FORMATETC* result) {
  854. format_etc->ptd = NULL;
  855. return E_NOTIMPL;
  856. }
  857. HRESULT DataObjectImpl::SetData(
  858. FORMATETC* format_etc, STGMEDIUM* medium, BOOL should_release) {
  859. RemoveData(*format_etc);
  860. // If `should_release` is true, ownership of the original data in `medium` is
  861. // transferred to `this`. Otherwise it remains with the caller. To prevent
  862. // lifetime issues, perform a deep copy of `medium`.
  863. STGMEDIUM local_medium =
  864. should_release ? *medium : DuplicateMedium(format_etc->cfFormat, *medium);
  865. DCHECK_EQ(local_medium.tymed, format_etc->tymed);
  866. auto info = StoredDataInfo::TakeStorageMedium(*format_etc, local_medium);
  867. // Make newly added data appear first.
  868. // TODO(dcheng): Make various setters agree whether elements should be
  869. // prioritized from front to back or back to front.
  870. contents_.insert(contents_.begin(), std::move(info));
  871. return S_OK;
  872. }
  873. HRESULT DataObjectImpl::EnumFormatEtc(
  874. DWORD direction, IEnumFORMATETC** enumerator) {
  875. if (direction == DATADIR_GET) {
  876. FormatEtcEnumerator* e =
  877. new FormatEtcEnumerator(contents_.begin(), contents_.end());
  878. e->AddRef();
  879. *enumerator = e;
  880. return S_OK;
  881. }
  882. return E_NOTIMPL;
  883. }
  884. HRESULT DataObjectImpl::DAdvise(
  885. FORMATETC* format_etc, DWORD advf, IAdviseSink* sink, DWORD* connection) {
  886. return OLE_E_ADVISENOTSUPPORTED;
  887. }
  888. HRESULT DataObjectImpl::DUnadvise(DWORD connection) {
  889. return OLE_E_ADVISENOTSUPPORTED;
  890. }
  891. HRESULT DataObjectImpl::EnumDAdvise(IEnumSTATDATA** enumerator) {
  892. return OLE_E_ADVISENOTSUPPORTED;
  893. }
  894. ///////////////////////////////////////////////////////////////////////////////
  895. // DataObjectImpl, IDataObjectAsyncCapability implementation:
  896. HRESULT DataObjectImpl::EndOperation(
  897. HRESULT result, IBindCtx* reserved, DWORD effects) {
  898. async_operation_started_ = false;
  899. return S_OK;
  900. }
  901. HRESULT DataObjectImpl::GetAsyncMode(BOOL* is_op_async) {
  902. *is_op_async = in_async_mode_ ? VARIANT_TRUE : VARIANT_FALSE;
  903. return S_OK;
  904. }
  905. HRESULT DataObjectImpl::InOperation(BOOL* in_async_op) {
  906. *in_async_op = async_operation_started_ ? VARIANT_TRUE : VARIANT_FALSE;
  907. return S_OK;
  908. }
  909. HRESULT DataObjectImpl::SetAsyncMode(BOOL do_op_async) {
  910. in_async_mode_ = !!do_op_async;
  911. return S_OK;
  912. }
  913. HRESULT DataObjectImpl::StartOperation(IBindCtx* reserved) {
  914. async_operation_started_ = true;
  915. return S_OK;
  916. }
  917. ///////////////////////////////////////////////////////////////////////////////
  918. // DataObjectImpl, IUnknown implementation:
  919. HRESULT DataObjectImpl::QueryInterface(const IID& iid, void** object) {
  920. if (!object)
  921. return E_POINTER;
  922. if (IsEqualIID(iid, IID_IDataObject) || IsEqualIID(iid, IID_IUnknown)) {
  923. *object = static_cast<IDataObject*>(this);
  924. } else if (in_async_mode_ &&
  925. IsEqualIID(iid, __uuidof(IDataObjectAsyncCapability))) {
  926. *object = static_cast<IDataObjectAsyncCapability*>(this);
  927. } else {
  928. *object = NULL;
  929. return E_NOINTERFACE;
  930. }
  931. AddRef();
  932. return S_OK;
  933. }
  934. ULONG DataObjectImpl::AddRef() {
  935. base::RefCountedThreadSafe<DownloadFileObserver>::AddRef();
  936. return 0;
  937. }
  938. ULONG DataObjectImpl::Release() {
  939. base::RefCountedThreadSafe<DownloadFileObserver>::Release();
  940. return 0;
  941. }
  942. ///////////////////////////////////////////////////////////////////////////////
  943. // anonymous namespace functions
  944. namespace {
  945. STGMEDIUM CreateStorageForBytes(const void* data, size_t bytes) {
  946. HANDLE handle = GlobalAlloc(GPTR, bytes);
  947. if (handle) {
  948. base::win::ScopedHGlobal<uint8_t*> scoped(handle);
  949. memcpy(scoped.get(), data, bytes);
  950. }
  951. STGMEDIUM storage = {
  952. .tymed = TYMED_HGLOBAL, .hGlobal = handle, .pUnkForRelease = nullptr};
  953. return storage;
  954. }
  955. template <typename T>
  956. STGMEDIUM CreateStorageForString(const std::basic_string<T>& data) {
  957. return CreateStorageForBytes(
  958. data.c_str(),
  959. (data.size() + 1) * sizeof(typename std::basic_string<T>::value_type));
  960. }
  961. LPITEMIDLIST PIDLNext(LPITEMIDLIST pidl) {
  962. return reinterpret_cast<LPITEMIDLIST>(
  963. reinterpret_cast<BYTE*>(pidl) + pidl->mkid.cb);
  964. }
  965. size_t PIDLSize(LPITEMIDLIST pidl) {
  966. size_t s = 0;
  967. while (pidl->mkid.cb > 0) {
  968. s += pidl->mkid.cb;
  969. pidl = PIDLNext(pidl);
  970. }
  971. // We add 2 because an LPITEMIDLIST is terminated by two NULL bytes.
  972. return 2 + s;
  973. }
  974. LPITEMIDLIST GetNthPIDL(CIDA* cida, int n) {
  975. return reinterpret_cast<LPITEMIDLIST>(
  976. reinterpret_cast<LPBYTE>(cida) + cida->aoffset[n]);
  977. }
  978. LPITEMIDLIST GetPidlFromPath(const base::FilePath& path) {
  979. LPITEMIDLIST pidl = NULL;
  980. LPSHELLFOLDER desktop_folder = NULL;
  981. LPWSTR path_str = const_cast<LPWSTR>(path.value().c_str());
  982. if (FAILED(SHGetDesktopFolder(&desktop_folder)))
  983. return NULL;
  984. HRESULT hr = desktop_folder->ParseDisplayName(
  985. NULL, NULL, path_str, NULL, &pidl, NULL);
  986. return SUCCEEDED(hr) ? pidl : NULL;
  987. }
  988. STGMEDIUM CreateIdListStorageForFileName(const base::FilePath& path) {
  989. LPITEMIDLIST pidl = GetPidlFromPath(path);
  990. if (!pidl)
  991. return kNullStorageMedium;
  992. // When using CFSTR_SHELLIDLIST the hGlobal field of the STGMEDIUM is a
  993. // pointer to a CIDA*. A CIDA is a variable length struct that contains a PIDL
  994. // count (a UINT), an array of offsets of the following PIDLs (a UINT[]) and
  995. // then a series of PIDLs laid out contiguously in memory. A PIDL is
  996. // represented by an ITEMIDLIST struct, which contains a single SHITEMID.
  997. // Despite only containing a single SHITEMID, ITEMIDLISTs are so-named because
  998. // SHITEMIDs contain their own size and so given one, the next can be found by
  999. // looking at the section of memory after it. The end of a list is indicated
  1000. // by two NULL bytes.
  1001. // Here we require two PIDLs - the first PIDL is the parent folder and is
  1002. // NULL here to indicate that the parent folder is the desktop, and the second
  1003. // is the PIDL of |path|.
  1004. const size_t kPIDLCountSize = sizeof(UINT);
  1005. const size_t kPIDLOffsetsSize = 2 * sizeof(UINT);
  1006. const size_t kFirstPIDLOffset = kPIDLCountSize + kPIDLOffsetsSize;
  1007. const size_t kFirstPIDLSize = 2; // Empty PIDL - 2 NULL bytes.
  1008. const size_t kSecondPIDLSize = PIDLSize(pidl);
  1009. const size_t kCIDASize = kFirstPIDLOffset + kFirstPIDLSize + kSecondPIDLSize;
  1010. HANDLE hdata = GlobalAlloc(GMEM_MOVEABLE, kCIDASize);
  1011. base::win::ScopedHGlobal<CIDA*> locked_mem(hdata);
  1012. CIDA* cida = locked_mem.get();
  1013. cida->cidl = 1; // We have one PIDL (not including the 0th root PIDL).
  1014. cida->aoffset[0] = kFirstPIDLOffset;
  1015. cida->aoffset[1] = kFirstPIDLOffset + kFirstPIDLSize;
  1016. LPITEMIDLIST idl = GetNthPIDL(cida, 0);
  1017. idl->mkid.cb = 0;
  1018. idl->mkid.abID[0] = 0;
  1019. idl = GetNthPIDL(cida, 1);
  1020. memcpy(idl, pidl, kSecondPIDLSize);
  1021. STGMEDIUM storage = {
  1022. .tymed = TYMED_HGLOBAL, .hGlobal = hdata, .pUnkForRelease = nullptr};
  1023. return storage;
  1024. }
  1025. STGMEDIUM CreateStorageForFileDescriptor(const base::FilePath& path) {
  1026. std::wstring file_name = path.value();
  1027. DCHECK(!file_name.empty());
  1028. HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTORW));
  1029. base::win::ScopedHGlobal<FILEGROUPDESCRIPTORW*> locked_mem(hdata);
  1030. FILEGROUPDESCRIPTORW* descriptor = locked_mem.get();
  1031. descriptor->cItems = 1;
  1032. descriptor->fgd[0].dwFlags = FD_LINKUI;
  1033. wcsncpy_s(descriptor->fgd[0].cFileName, MAX_PATH, file_name.c_str(),
  1034. std::min(file_name.size(), static_cast<size_t>(MAX_PATH - 1u)));
  1035. STGMEDIUM storage = {
  1036. .tymed = TYMED_HGLOBAL, .hGlobal = hdata, .pUnkForRelease = nullptr};
  1037. return storage;
  1038. }
  1039. const ClipboardFormatType& GetRendererTaintFormatType() {
  1040. static base::NoDestructor<ClipboardFormatType> format(
  1041. ClipboardFormatType::GetType("chromium/x-renderer-taint"));
  1042. return *format;
  1043. }
  1044. const ClipboardFormatType& GetFromPrivilegedFormatType() {
  1045. static base::NoDestructor<ClipboardFormatType> format(
  1046. ClipboardFormatType::GetType("chromium/from-privileged"));
  1047. return *format;
  1048. }
  1049. // Used to mark file content as synthesized by Chrome itself during a non-file
  1050. // drag for interoperating with the native OS. Synthesized file contents will be
  1051. // treated as non-existent for the purposes of GetFileContent() to avoid
  1052. // confusing web pages that might not expect the synthesized file. See
  1053. // https://crbug.com/1274395 for background.
  1054. const ClipboardFormatType& GetIgnoreFileContentsFormatType() {
  1055. static base::NoDestructor<ClipboardFormatType> format(
  1056. ClipboardFormatType::GetType("chromium/x-ignore-file-contents"));
  1057. return *format;
  1058. }
  1059. std::string GetInternetShortcutFileContents(const GURL& url) {
  1060. static constexpr char kInternetShortcutFileStart[] =
  1061. "[InternetShortcut]\r\nURL=";
  1062. static constexpr char kInternetShortcutFileEnd[] = "\r\n";
  1063. return kInternetShortcutFileStart + url.spec() + kInternetShortcutFileEnd;
  1064. }
  1065. std::wstring CreateValidFileNameFromTitle(const GURL& url,
  1066. const std::wstring& title) {
  1067. std::wstring validated;
  1068. if (title.empty()) {
  1069. if (url.is_valid()) {
  1070. validated = base::AsWString(
  1071. net::GetSuggestedFilename(url, "", "", "", "", std::string()));
  1072. } else {
  1073. // Nothing else can be done, just use a default.
  1074. validated = l10n_util::GetWideString(IDS_APP_UNTITLED_SHORTCUT_FILE_NAME);
  1075. }
  1076. } else {
  1077. validated = title;
  1078. base::i18n::ReplaceIllegalCharactersInPath(&validated, '-');
  1079. }
  1080. static const wchar_t kExtension[] = L".url";
  1081. // The value of kMaxFileNameLength was chosen to account for local file paths
  1082. // that can cause total paths to be greater than MAX_PATH while still allowing
  1083. // for a relatively long title. The total path may still exceed MAX_PATH when
  1084. // the local path length exceeds MAX_PATH - kMaxFileNameLength. See
  1085. // crbug.com/779414.
  1086. static constexpr size_t kMaxFileNameLength = MAX_PATH / 2;
  1087. // Maximum length of title after truncation.
  1088. static constexpr size_t kMaxFileTitleLength =
  1089. kMaxFileNameLength - std::size(kExtension);
  1090. if (validated.size() > kMaxFileTitleLength)
  1091. validated.erase(kMaxFileTitleLength);
  1092. validated += kExtension;
  1093. return validated;
  1094. }
  1095. } // namespace
  1096. } // namespace ui