2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "ClipboardUtilitiesWin.h"
29 #include "DocumentFragment.h"
31 #include "TextEncoding.h"
35 #include <wininet.h> // for INTERNET_MAX_URL_LENGTH
36 #include <wtf/StringExtras.h>
37 #include <wtf/text/CString.h>
38 #include <wtf/text/WTFString.h>
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <wtf/RetainPtr.h>
48 FORMATETC* cfHDropFormat()
50 static FORMATETC urlFormat = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
54 static bool urlFromPath(CFStringRef path, String& url)
59 RetainPtr<CFURLRef> cfURL(AdoptCF, CFURLCreateWithFileSystemPath(0, path, kCFURLWindowsPathStyle, false));
63 url = CFURLGetString(cfURL.get());
65 // Work around <rdar://problem/6708300>, where CFURLCreateWithFileSystemPath makes URLs with "localhost".
66 if (url.startsWith("file://localhost/"))
73 static bool getDataMapItem(const DragDataMap* dataObject, FORMATETC* format, String& item)
75 DragDataMap::const_iterator found = dataObject->find(format->cfFormat);
76 if (found == dataObject->end())
78 item = found->second[0];
82 static bool getWebLocData(IDataObject* dataObject, String& url, String* title)
84 bool succeeded = false;
86 WCHAR filename[MAX_PATH];
87 WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH];
90 if (FAILED(dataObject->GetData(cfHDropFormat(), &medium)))
93 HDROP hdrop = static_cast<HDROP>(GlobalLock(medium.hGlobal));
98 if (!DragQueryFileW(hdrop, 0, filename, WTF_ARRAY_LENGTH(filename)))
101 if (_wcsicmp(PathFindExtensionW(filename), L".url"))
104 if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF_ARRAY_LENGTH(urlBuffer), filename))
108 PathRemoveExtension(filename);
109 *title = String((UChar*)filename);
112 url = String((UChar*)urlBuffer);
118 GlobalUnlock(medium.hGlobal);
123 static bool getWebLocData(const DragDataMap* dataObject, String& url, String* title)
126 WCHAR filename[MAX_PATH];
127 WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH];
129 if (!dataObject->contains(cfHDropFormat()->cfFormat))
132 wcscpy(filename, dataObject->get(cfHDropFormat()->cfFormat)[0].charactersWithNullTermination());
133 if (_wcsicmp(PathFindExtensionW(filename), L".url"))
136 if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF_ARRAY_LENGTH(urlBuffer), filename))
140 PathRemoveExtension(filename);
151 static String extractURL(const String &inURL, String* title)
154 int splitLoc = url.find('\n');
157 *title = url.substring(splitLoc+1);
158 url.truncate(splitLoc);
165 static FORMATETC* texthtmlFormat()
167 static UINT cf = RegisterClipboardFormat(L"text/html");
168 static FORMATETC texthtmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
169 return &texthtmlFormat;
172 HGLOBAL createGlobalData(const KURL& url, const String& title)
174 String mutableURL(url.string());
175 String mutableTitle(title);
176 SIZE_T size = mutableURL.length() + mutableTitle.length() + 2; // +1 for "\n" and +1 for null terminator
177 HGLOBAL cbData = ::GlobalAlloc(GPTR, size * sizeof(UChar));
180 PWSTR buffer = static_cast<PWSTR>(GlobalLock(cbData));
181 _snwprintf(buffer, size, L"%s\n%s", mutableURL.charactersWithNullTermination(), mutableTitle.charactersWithNullTermination());
182 GlobalUnlock(cbData);
187 HGLOBAL createGlobalData(const String& str)
189 HGLOBAL globalData = ::GlobalAlloc(GPTR, (str.length() + 1) * sizeof(UChar));
192 UChar* buffer = static_cast<UChar*>(GlobalLock(globalData));
193 memcpy(buffer, str.characters(), str.length() * sizeof(UChar));
194 buffer[str.length()] = 0;
195 GlobalUnlock(globalData);
199 HGLOBAL createGlobalData(const Vector<char>& vector)
201 HGLOBAL globalData = ::GlobalAlloc(GPTR, vector.size() + 1);
204 char* buffer = static_cast<char*>(GlobalLock(globalData));
205 memcpy(buffer, vector.data(), vector.size());
206 buffer[vector.size()] = 0;
207 GlobalUnlock(globalData);
211 static String getFullCFHTML(IDataObject* data, bool& success)
214 if (SUCCEEDED(data->GetData(htmlFormat(), &store))) {
215 // MS HTML Format parsing
216 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
217 SIZE_T dataSize = ::GlobalSize(store.hGlobal);
218 String cfhtml(UTF8Encoding().decode(data, dataSize));
219 GlobalUnlock(store.hGlobal);
220 ReleaseStgMedium(&store);
228 static void append(Vector<char>& vector, const char* string)
230 vector.append(string, strlen(string));
233 static void append(Vector<char>& vector, const CString& string)
235 vector.append(string.data(), string.length());
238 // Find the markup between "<!--StartFragment -->" and "<!--EndFragment -->", accounting for browser quirks.
239 static String extractMarkupFromCFHTML(const String& cfhtml)
241 unsigned markupStart = cfhtml.find("<html", 0, false);
242 unsigned tagStart = cfhtml.find("startfragment", markupStart, false);
243 unsigned fragmentStart = cfhtml.find('>', tagStart) + 1;
244 unsigned tagEnd = cfhtml.find("endfragment", fragmentStart, false);
245 unsigned fragmentEnd = cfhtml.reverseFind('<', tagEnd);
246 return cfhtml.substring(fragmentStart, fragmentEnd - fragmentStart).stripWhiteSpace();
249 // Documentation for the CF_HTML format is available at http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp
250 void markupToCFHTML(const String& markup, const String& srcURL, Vector<char>& result)
252 if (markup.isEmpty())
255 #define MAX_DIGITS 10
256 #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits)
257 #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u"
258 #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS)
260 const char* header = "Version:0.9\n"
261 "StartHTML:" NUMBER_FORMAT "\n"
262 "EndHTML:" NUMBER_FORMAT "\n"
263 "StartFragment:" NUMBER_FORMAT "\n"
264 "EndFragment:" NUMBER_FORMAT "\n";
265 const char* sourceURLPrefix = "SourceURL:";
267 const char* startMarkup = "<HTML>\n<BODY>\n<!--StartFragment-->\n";
268 const char* endMarkup = "\n<!--EndFragment-->\n</BODY>\n</HTML>";
270 CString sourceURLUTF8 = srcURL == blankURL() ? "" : srcURL.utf8();
271 CString markupUTF8 = markup.utf8();
274 unsigned startHTMLOffset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4;
275 if (sourceURLUTF8.length())
276 startHTMLOffset += strlen(sourceURLPrefix) + sourceURLUTF8.length() + 1;
277 unsigned startFragmentOffset = startHTMLOffset + strlen(startMarkup);
278 unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length();
279 unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup);
281 unsigned headerBufferLength = startHTMLOffset + 1; // + 1 for '\0' terminator.
282 char* headerBuffer = (char*)malloc(headerBufferLength);
283 snprintf(headerBuffer, headerBufferLength, header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset);
284 append(result, CString(headerBuffer));
286 if (sourceURLUTF8.length()) {
287 append(result, sourceURLPrefix);
288 append(result, sourceURLUTF8);
291 append(result, startMarkup);
292 append(result, markupUTF8);
293 append(result, endMarkup);
296 #undef MAKE_NUMBER_FORMAT_1
297 #undef MAKE_NUMBER_FORMAT_2
301 void replaceNewlinesWithWindowsStyleNewlines(String& str)
303 static const UChar Newline = '\n';
304 static const char* const WindowsNewline("\r\n");
305 str.replace(Newline, WindowsNewline);
308 void replaceNBSPWithSpace(String& str)
310 static const UChar NonBreakingSpaceCharacter = 0xA0;
311 static const UChar SpaceCharacter = ' ';
312 str.replace(NonBreakingSpaceCharacter, SpaceCharacter);
315 FORMATETC* urlWFormat()
317 static UINT cf = RegisterClipboardFormat(L"UniformResourceLocatorW");
318 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
322 FORMATETC* urlFormat()
324 static UINT cf = RegisterClipboardFormat(L"UniformResourceLocator");
325 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
329 FORMATETC* plainTextFormat()
331 static FORMATETC textFormat = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
335 FORMATETC* plainTextWFormat()
337 static FORMATETC textFormat = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
341 FORMATETC* filenameWFormat()
343 static UINT cf = RegisterClipboardFormat(L"FileNameW");
344 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
348 FORMATETC* filenameFormat()
350 static UINT cf = RegisterClipboardFormat(L"FileName");
351 static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
356 FORMATETC* htmlFormat()
358 static UINT cf = RegisterClipboardFormat(L"HTML Format");
359 static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
363 FORMATETC* smartPasteFormat()
365 static UINT cf = RegisterClipboardFormat(L"WebKit Smart Paste Format");
366 static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
370 FORMATETC* fileDescriptorFormat()
372 static UINT cf = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
373 static FORMATETC fileDescriptorFormat = { cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
374 return &fileDescriptorFormat;
377 FORMATETC* fileContentFormatZero()
379 static UINT cf = RegisterClipboardFormat(CFSTR_FILECONTENTS);
380 static FORMATETC fileContentFormat = { cf, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL };
381 return &fileContentFormat;
384 void getFileDescriptorData(IDataObject* dataObject, int& size, String& pathname)
388 if (FAILED(dataObject->GetData(fileDescriptorFormat(), &store)))
391 FILEGROUPDESCRIPTOR* fgd = static_cast<FILEGROUPDESCRIPTOR*>(GlobalLock(store.hGlobal));
392 size = fgd->fgd[0].nFileSizeLow;
393 pathname = fgd->fgd[0].cFileName;
395 GlobalUnlock(store.hGlobal);
396 ::ReleaseStgMedium(&store);
399 void getFileContentData(IDataObject* dataObject, int size, void* dataBlob)
402 if (FAILED(dataObject->GetData(fileContentFormatZero(), &store)))
404 void* data = GlobalLock(store.hGlobal);
405 ::CopyMemory(dataBlob, data, size);
407 GlobalUnlock(store.hGlobal);
408 ::ReleaseStgMedium(&store);
411 void setFileDescriptorData(IDataObject* dataObject, int size, const String& passedPathname)
413 String pathname = passedPathname;
415 STGMEDIUM medium = { 0 };
416 medium.tymed = TYMED_HGLOBAL;
418 medium.hGlobal = ::GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
422 FILEGROUPDESCRIPTOR* fgd = static_cast<FILEGROUPDESCRIPTOR*>(GlobalLock(medium.hGlobal));
423 ::ZeroMemory(fgd, sizeof(FILEGROUPDESCRIPTOR));
425 fgd->fgd[0].dwFlags = FD_FILESIZE;
426 fgd->fgd[0].nFileSizeLow = size;
428 int maxSize = std::min(pathname.length(), WTF_ARRAY_LENGTH(fgd->fgd[0].cFileName));
429 CopyMemory(fgd->fgd[0].cFileName, pathname.charactersWithNullTermination(), maxSize * sizeof(UChar));
430 GlobalUnlock(medium.hGlobal);
432 dataObject->SetData(fileDescriptorFormat(), &medium, TRUE);
435 void setFileContentData(IDataObject* dataObject, int size, void* dataBlob)
437 STGMEDIUM medium = { 0 };
438 medium.tymed = TYMED_HGLOBAL;
440 medium.hGlobal = ::GlobalAlloc(GPTR, size);
443 void* fileContents = GlobalLock(medium.hGlobal);
444 ::CopyMemory(fileContents, dataBlob, size);
445 GlobalUnlock(medium.hGlobal);
447 dataObject->SetData(fileContentFormatZero(), &medium, TRUE);
450 String getURL(IDataObject* dataObject, DragData::FilenameConversionPolicy filenamePolicy, bool& success, String* title)
455 if (getWebLocData(dataObject, url, title))
457 else if (SUCCEEDED(dataObject->GetData(urlWFormat(), &store))) {
459 UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal));
460 url = extractURL(String(data), title);
461 GlobalUnlock(store.hGlobal);
462 ReleaseStgMedium(&store);
464 } else if (SUCCEEDED(dataObject->GetData(urlFormat(), &store))) {
466 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
467 url = extractURL(String(data), title);
468 GlobalUnlock(store.hGlobal);
469 ReleaseStgMedium(&store);
473 else if (filenamePolicy == DragData::ConvertFilenames) {
474 if (SUCCEEDED(dataObject->GetData(filenameWFormat(), &store))) {
475 // file using unicode
476 wchar_t* data = static_cast<wchar_t*>(GlobalLock(store.hGlobal));
477 if (data && data[0] && (PathFileExists(data) || PathIsUNC(data))) {
478 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar*)data, wcslen(data)));
479 if (urlFromPath(pathAsCFString.get(), url)) {
485 GlobalUnlock(store.hGlobal);
486 ReleaseStgMedium(&store);
487 } else if (SUCCEEDED(dataObject->GetData(filenameFormat(), &store))) {
488 // filename using ascii
489 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
490 if (data && data[0] && (PathFileExistsA(data) || PathIsUNCA(data))) {
491 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, data, kCFStringEncodingASCII));
492 if (urlFromPath(pathAsCFString.get(), url)) {
498 GlobalUnlock(store.hGlobal);
499 ReleaseStgMedium(&store);
506 String getURL(const DragDataMap* data, DragData::FilenameConversionPolicy filenamePolicy, String* title)
510 if (getWebLocData(data, url, title))
512 if (getDataMapItem(data, urlWFormat(), url))
513 return extractURL(url, title);
514 if (getDataMapItem(data, urlFormat(), url))
515 return extractURL(url, title);
517 if (filenamePolicy != DragData::ConvertFilenames)
521 if (!getDataMapItem(data, filenameWFormat(), stringData))
522 getDataMapItem(data, filenameFormat(), stringData);
524 if (stringData.isEmpty() || (!PathFileExists(stringData.charactersWithNullTermination()) && !PathIsUNC(stringData.charactersWithNullTermination())))
526 RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar *)stringData.charactersWithNullTermination(), wcslen(stringData.charactersWithNullTermination())));
527 if (urlFromPath(pathAsCFString.get(), url) && title)
533 String getPlainText(IDataObject* dataObject, bool& success)
538 if (SUCCEEDED(dataObject->GetData(plainTextWFormat(), &store))) {
540 UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal));
542 GlobalUnlock(store.hGlobal);
543 ReleaseStgMedium(&store);
545 } else if (SUCCEEDED(dataObject->GetData(plainTextFormat(), &store))) {
547 char* data = static_cast<char*>(GlobalLock(store.hGlobal));
549 GlobalUnlock(store.hGlobal);
550 ReleaseStgMedium(&store);
553 // FIXME: Originally, we called getURL() here because dragging and dropping files doesn't
554 // populate the drag with text data. Per https://bugs.webkit.org/show_bug.cgi?id=38826, this
555 // is undesirable, so maybe this line can be removed.
556 text = getURL(dataObject, DragData::DoNotConvertFilenames, success);
562 String getPlainText(const DragDataMap* data)
566 if (getDataMapItem(data, plainTextWFormat(), text))
568 if (getDataMapItem(data, plainTextFormat(), text))
570 return getURL(data, DragData::DoNotConvertFilenames);
573 String getTextHTML(IDataObject* data, bool& success)
578 if (SUCCEEDED(data->GetData(texthtmlFormat(), &store))) {
579 UChar* data = static_cast<UChar*>(GlobalLock(store.hGlobal));
581 GlobalUnlock(store.hGlobal);
582 ReleaseStgMedium(&store);
588 String getTextHTML(const DragDataMap* data)
591 getDataMapItem(data, texthtmlFormat(), text);
595 String getCFHTML(IDataObject* data, bool& success)
597 String cfhtml = getFullCFHTML(data, success);
599 return extractMarkupFromCFHTML(cfhtml);
603 String getCFHTML(const DragDataMap* dataMap)
606 getDataMapItem(dataMap, htmlFormat(), cfhtml);
607 return extractMarkupFromCFHTML(cfhtml);
610 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*)
612 // FIXME: We should be able to create fragments from files
616 PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const DragDataMap*)
618 // FIXME: We should be able to create fragments from files
622 bool containsFilenames(const IDataObject*)
624 // FIXME: We'll want to update this once we can produce fragments from files
628 bool containsFilenames(const DragDataMap*)
630 // FIXME: We'll want to update this once we can produce fragments from files
634 // Convert a String containing CF_HTML formatted text to a DocumentFragment
635 PassRefPtr<DocumentFragment> fragmentFromCFHTML(Document* doc, const String& cfhtml)
637 // obtain baseURL if present
638 String srcURLStr("sourceURL:");
640 unsigned lineStart = cfhtml.find(srcURLStr, 0, false);
641 if (lineStart != -1) {
642 unsigned srcEnd = cfhtml.find("\n", lineStart, false);
643 unsigned srcStart = lineStart+srcURLStr.length();
644 String rawSrcURL = cfhtml.substring(srcStart, srcEnd-srcStart);
645 replaceNBSPWithSpace(rawSrcURL);
646 srcURL = rawSrcURL.stripWhiteSpace();
649 String markup = extractMarkupFromCFHTML(cfhtml);
650 return createFragmentFromMarkup(doc, markup, srcURL, FragmentScriptingNotAllowed);
653 PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data)
658 bool success = false;
659 String cfhtml = getFullCFHTML(data, success);
661 if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(doc, cfhtml))
662 return fragment.release();
665 String html = getTextHTML(data, success);
668 return createFragmentFromMarkup(doc, html, srcURL, FragmentScriptingNotAllowed);
673 PassRefPtr<DocumentFragment> fragmentFromHTML(Document* document, const DragDataMap* data)
675 if (!document || !data || data->isEmpty())
679 if (getDataMapItem(data, htmlFormat(), stringData)) {
680 if (RefPtr<DocumentFragment> fragment = fragmentFromCFHTML(document, stringData))
681 return fragment.release();
685 if (getDataMapItem(data, texthtmlFormat(), stringData))
686 return createFragmentFromMarkup(document, stringData, srcURL, FragmentScriptingNotAllowed);
691 bool containsHTML(IDataObject* data)
693 return SUCCEEDED(data->QueryGetData(texthtmlFormat())) || SUCCEEDED(data->QueryGetData(htmlFormat()));
696 bool containsHTML(const DragDataMap* data)
698 return data->contains(texthtmlFormat()->cfFormat) || data->contains(htmlFormat()->cfFormat);
701 typedef void (*GetStringFunction)(IDataObject*, FORMATETC*, Vector<String>&);
702 typedef void (*SetStringFunction)(IDataObject*, FORMATETC*, const Vector<String>&);
704 struct ClipboardDataItem {
705 GetStringFunction getString;
706 SetStringFunction setString;
709 ClipboardDataItem(FORMATETC* format, GetStringFunction getString, SetStringFunction setString): format(format), getString(getString), setString(setString) { }
712 typedef HashMap<UINT, ClipboardDataItem*> ClipboardFormatMap;
716 template<typename T> void getStringData(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
719 if (FAILED(data->GetData(format, &store)))
721 dataStrings.append(String(static_cast<T*>(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T)));
722 GlobalUnlock(store.hGlobal);
723 ReleaseStgMedium(&store);
726 void getUtf8Data(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
729 if (FAILED(data->GetData(format, &store)))
731 dataStrings.append(String(UTF8Encoding().decode(static_cast<char*>(GlobalLock(store.hGlobal)), GlobalSize(store.hGlobal))));
732 GlobalUnlock(store.hGlobal);
733 ReleaseStgMedium(&store);
737 void getCFData(IDataObject* data, FORMATETC* format, Vector<String>& dataStrings)
740 if (FAILED(data->GetData(format, &store)))
743 HDROP hdrop = reinterpret_cast<HDROP>(GlobalLock(store.hGlobal));
747 WCHAR filename[MAX_PATH];
748 UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
749 for (UINT i = 0; i < fileCount; i++) {
750 if (!DragQueryFileW(hdrop, i, filename, WTF_ARRAY_LENGTH(filename)))
752 dataStrings.append(static_cast<UChar*>(filename));
755 GlobalUnlock(store.hGlobal);
756 ReleaseStgMedium(&store);
762 void setUCharData(IDataObject* data, FORMATETC* format, const Vector<String>& dataStrings)
764 STGMEDIUM medium = {0};
765 medium.tymed = TYMED_HGLOBAL;
767 medium.hGlobal = createGlobalData(dataStrings.first());
770 data->SetData(format, &medium, FALSE);
771 ::GlobalFree(medium.hGlobal);
774 void setUtf8Data(IDataObject* data, FORMATETC* format, const Vector<String>& dataStrings)
776 STGMEDIUM medium = {0};
777 medium.tymed = TYMED_HGLOBAL;
779 CString charString = dataStrings.first().utf8();
780 size_t stringLength = charString.length();
781 medium.hGlobal = ::GlobalAlloc(GPTR, stringLength + 1);
784 char* buffer = static_cast<char*>(GlobalLock(medium.hGlobal));
785 memcpy(buffer, charString.data(), stringLength);
786 buffer[stringLength] = 0;
787 GlobalUnlock(medium.hGlobal);
788 data->SetData(format, &medium, FALSE);
789 ::GlobalFree(medium.hGlobal);
793 void setCFData(IDataObject* data, FORMATETC* format, const Vector<String>& dataStrings)
795 STGMEDIUM medium = {0};
796 medium.tymed = TYMED_HGLOBAL;
798 SIZE_T dropFilesSize = sizeof(DROPFILES) + (sizeof(WCHAR) * (dataStrings.first().length() + 2));
799 medium.hGlobal = ::GlobalAlloc(GHND | GMEM_SHARE, dropFilesSize);
803 DROPFILES* dropFiles = reinterpret_cast<DROPFILES *>(GlobalLock(medium.hGlobal));
804 dropFiles->pFiles = sizeof(DROPFILES);
805 dropFiles->fWide = TRUE;
806 String filename = dataStrings.first();
807 wcscpy(reinterpret_cast<LPWSTR>(dropFiles + 1), filename.charactersWithNullTermination());
808 GlobalUnlock(medium.hGlobal);
809 data->SetData(format, &medium, FALSE);
810 ::GlobalFree(medium.hGlobal);
814 static const ClipboardFormatMap& getClipboardMap()
816 static ClipboardFormatMap formatMap;
817 if (formatMap.isEmpty()) {
818 formatMap.add(htmlFormat()->cfFormat, new ClipboardDataItem(htmlFormat(), getUtf8Data, setUtf8Data));
819 formatMap.add(texthtmlFormat()->cfFormat, new ClipboardDataItem(texthtmlFormat(), getStringData<UChar>, setUCharData));
820 formatMap.add(plainTextFormat()->cfFormat, new ClipboardDataItem(plainTextFormat(), getStringData<char>, setUtf8Data));
821 formatMap.add(plainTextWFormat()->cfFormat, new ClipboardDataItem(plainTextWFormat(), getStringData<UChar>, setUCharData));
823 formatMap.add(cfHDropFormat()->cfFormat, new ClipboardDataItem(cfHDropFormat(), getCFData, setCFData));
825 formatMap.add(filenameFormat()->cfFormat, new ClipboardDataItem(filenameFormat(), getStringData<char>, setUtf8Data));
826 formatMap.add(filenameWFormat()->cfFormat, new ClipboardDataItem(filenameWFormat(), getStringData<UChar>, setUCharData));
827 formatMap.add(urlFormat()->cfFormat, new ClipboardDataItem(urlFormat(), getStringData<char>, setUtf8Data));
828 formatMap.add(urlWFormat()->cfFormat, new ClipboardDataItem(urlWFormat(), getStringData<UChar>, setUCharData));
833 void getClipboardData(IDataObject* dataObject, FORMATETC* format, Vector<String>& dataStrings)
835 const ClipboardFormatMap& formatMap = getClipboardMap();
836 ClipboardFormatMap::const_iterator found = formatMap.find(format->cfFormat);
837 if (found == formatMap.end())
839 found->second->getString(dataObject, found->second->format, dataStrings);
842 void setClipboardData(IDataObject* dataObject, UINT format, const Vector<String>& dataStrings)
844 const ClipboardFormatMap& formatMap = getClipboardMap();
845 ClipboardFormatMap::const_iterator found = formatMap.find(format);
846 if (found == formatMap.end())
848 found->second->setString(dataObject, found->second->format, dataStrings);
851 } // namespace WebCore