/* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "ClipboardUtilitiesWin.h" #include "DocumentFragment.h" #include "KURL.h" #include "PlatformString.h" #include "TextEncoding.h" #include "markup.h" #include #include #include // for INTERNET_MAX_URL_LENGTH #include #include #include #if USE(CF) #include #include #endif namespace WebCore { #if USE(CF) FORMATETC* cfHDropFormat() { static FORMATETC urlFormat = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat; } static bool urlFromPath(CFStringRef path, String& url) { if (!path) return false; RetainPtr cfURL(AdoptCF, CFURLCreateWithFileSystemPath(0, path, kCFURLWindowsPathStyle, false)); if (!cfURL) return false; url = CFURLGetString(cfURL.get()); // Work around , where CFURLCreateWithFileSystemPath makes URLs with "localhost". if (url.startsWith("file://localhost/")) url.remove(7, 9); return true; } #endif static bool getDataMapItem(const DragDataMap* dataObject, FORMATETC* format, String& item) { DragDataMap::const_iterator found = dataObject->find(format->cfFormat); if (found == dataObject->end()) return false; item = found->second[0]; return true; } static bool getWebLocData(IDataObject* dataObject, String& url, String* title) { bool succeeded = false; #if USE(CF) WCHAR filename[MAX_PATH]; WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH]; STGMEDIUM medium; if (FAILED(dataObject->GetData(cfHDropFormat(), &medium))) return false; HDROP hdrop = static_cast(GlobalLock(medium.hGlobal)); if (!hdrop) return false; if (!DragQueryFileW(hdrop, 0, filename, WTF_ARRAY_LENGTH(filename))) goto exit; if (_wcsicmp(PathFindExtensionW(filename), L".url")) goto exit; if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF_ARRAY_LENGTH(urlBuffer), filename)) goto exit; if (title) { PathRemoveExtension(filename); *title = String((UChar*)filename); } url = String((UChar*)urlBuffer); succeeded = true; exit: // Free up memory. DragFinish(hdrop); GlobalUnlock(medium.hGlobal); #endif return succeeded; } static bool getWebLocData(const DragDataMap* dataObject, String& url, String* title) { #if USE(CF) WCHAR filename[MAX_PATH]; WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH]; if (!dataObject->contains(cfHDropFormat()->cfFormat)) return false; wcscpy(filename, dataObject->get(cfHDropFormat()->cfFormat)[0].charactersWithNullTermination()); if (_wcsicmp(PathFindExtensionW(filename), L".url")) return false; if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, WTF_ARRAY_LENGTH(urlBuffer), filename)) return false; if (title) { PathRemoveExtension(filename); *title = filename; } url = urlBuffer; return true; #else return false; #endif } static String extractURL(const String &inURL, String* title) { String url = inURL; int splitLoc = url.find('\n'); if (splitLoc > 0) { if (title) *title = url.substring(splitLoc+1); url.truncate(splitLoc); } else if (title) *title = url; return url; } // Firefox text/html static FORMATETC* texthtmlFormat() { static UINT cf = RegisterClipboardFormat(L"text/html"); static FORMATETC texthtmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &texthtmlFormat; } HGLOBAL createGlobalData(const KURL& url, const String& title) { String mutableURL(url.string()); String mutableTitle(title); SIZE_T size = mutableURL.length() + mutableTitle.length() + 2; // +1 for "\n" and +1 for null terminator HGLOBAL cbData = ::GlobalAlloc(GPTR, size * sizeof(UChar)); if (cbData) { PWSTR buffer = static_cast(GlobalLock(cbData)); _snwprintf(buffer, size, L"%s\n%s", mutableURL.charactersWithNullTermination(), mutableTitle.charactersWithNullTermination()); GlobalUnlock(cbData); } return cbData; } HGLOBAL createGlobalData(const String& str) { HGLOBAL globalData = ::GlobalAlloc(GPTR, (str.length() + 1) * sizeof(UChar)); if (!globalData) return 0; UChar* buffer = static_cast(GlobalLock(globalData)); memcpy(buffer, str.characters(), str.length() * sizeof(UChar)); buffer[str.length()] = 0; GlobalUnlock(globalData); return globalData; } HGLOBAL createGlobalData(const Vector& vector) { HGLOBAL globalData = ::GlobalAlloc(GPTR, vector.size() + 1); if (!globalData) return 0; char* buffer = static_cast(GlobalLock(globalData)); memcpy(buffer, vector.data(), vector.size()); buffer[vector.size()] = 0; GlobalUnlock(globalData); return globalData; } static String getFullCFHTML(IDataObject* data, bool& success) { STGMEDIUM store; if (SUCCEEDED(data->GetData(htmlFormat(), &store))) { // MS HTML Format parsing char* data = static_cast(GlobalLock(store.hGlobal)); SIZE_T dataSize = ::GlobalSize(store.hGlobal); String cfhtml(UTF8Encoding().decode(data, dataSize)); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; return cfhtml; } success = false; return String(); } static void append(Vector& vector, const char* string) { vector.append(string, strlen(string)); } static void append(Vector& vector, const CString& string) { vector.append(string.data(), string.length()); } // Find the markup between "" and "", accounting for browser quirks. static String extractMarkupFromCFHTML(const String& cfhtml) { unsigned markupStart = cfhtml.find("', tagStart) + 1; unsigned tagEnd = cfhtml.find("endfragment", fragmentStart, false); unsigned fragmentEnd = cfhtml.reverseFind('<', tagEnd); return cfhtml.substring(fragmentStart, fragmentEnd - fragmentStart).stripWhiteSpace(); } // Documentation for the CF_HTML format is available at http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp void markupToCFHTML(const String& markup, const String& srcURL, Vector& result) { if (markup.isEmpty()) return; #define MAX_DIGITS 10 #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits) #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u" #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS) const char* header = "Version:0.9\n" "StartHTML:" NUMBER_FORMAT "\n" "EndHTML:" NUMBER_FORMAT "\n" "StartFragment:" NUMBER_FORMAT "\n" "EndFragment:" NUMBER_FORMAT "\n"; const char* sourceURLPrefix = "SourceURL:"; const char* startMarkup = "\n\n\n"; const char* endMarkup = "\n\n\n"; CString sourceURLUTF8 = srcURL == blankURL() ? "" : srcURL.utf8(); CString markupUTF8 = markup.utf8(); // calculate offsets unsigned startHTMLOffset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4; if (sourceURLUTF8.length()) startHTMLOffset += strlen(sourceURLPrefix) + sourceURLUTF8.length() + 1; unsigned startFragmentOffset = startHTMLOffset + strlen(startMarkup); unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length(); unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup); unsigned headerBufferLength = startHTMLOffset + 1; // + 1 for '\0' terminator. char* headerBuffer = (char*)malloc(headerBufferLength); snprintf(headerBuffer, headerBufferLength, header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset); append(result, CString(headerBuffer)); free(headerBuffer); if (sourceURLUTF8.length()) { append(result, sourceURLPrefix); append(result, sourceURLUTF8); result.append('\n'); } append(result, startMarkup); append(result, markupUTF8); append(result, endMarkup); #undef MAX_DIGITS #undef MAKE_NUMBER_FORMAT_1 #undef MAKE_NUMBER_FORMAT_2 #undef NUMBER_FORMAT } void replaceNewlinesWithWindowsStyleNewlines(String& str) { static const UChar Newline = '\n'; static const char* const WindowsNewline("\r\n"); str.replace(Newline, WindowsNewline); } void replaceNBSPWithSpace(String& str) { static const UChar NonBreakingSpaceCharacter = 0xA0; static const UChar SpaceCharacter = ' '; str.replace(NonBreakingSpaceCharacter, SpaceCharacter); } FORMATETC* urlWFormat() { static UINT cf = RegisterClipboardFormat(L"UniformResourceLocatorW"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat; } FORMATETC* urlFormat() { static UINT cf = RegisterClipboardFormat(L"UniformResourceLocator"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat; } FORMATETC* plainTextFormat() { static FORMATETC textFormat = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &textFormat; } FORMATETC* plainTextWFormat() { static FORMATETC textFormat = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &textFormat; } FORMATETC* filenameWFormat() { static UINT cf = RegisterClipboardFormat(L"FileNameW"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat; } FORMATETC* filenameFormat() { static UINT cf = RegisterClipboardFormat(L"FileName"); static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &urlFormat; } // MSIE HTML Format FORMATETC* htmlFormat() { static UINT cf = RegisterClipboardFormat(L"HTML Format"); static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &htmlFormat; } FORMATETC* smartPasteFormat() { static UINT cf = RegisterClipboardFormat(L"WebKit Smart Paste Format"); static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return &htmlFormat; } String getURL(IDataObject* dataObject, DragData::FilenameConversionPolicy filenamePolicy, bool& success, String* title) { STGMEDIUM store; String url; success = false; if (getWebLocData(dataObject, url, title)) success = true; else if (SUCCEEDED(dataObject->GetData(urlWFormat(), &store))) { // URL using Unicode UChar* data = static_cast(GlobalLock(store.hGlobal)); url = extractURL(String(data), title); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } else if (SUCCEEDED(dataObject->GetData(urlFormat(), &store))) { // URL using ASCII char* data = static_cast(GlobalLock(store.hGlobal)); url = extractURL(String(data), title); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } #if USE(CF) else if (filenamePolicy == DragData::ConvertFilenames) { if (SUCCEEDED(dataObject->GetData(filenameWFormat(), &store))) { // file using unicode wchar_t* data = static_cast(GlobalLock(store.hGlobal)); if (data && data[0] && (PathFileExists(data) || PathIsUNC(data))) { RetainPtr pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar*)data, wcslen(data))); if (urlFromPath(pathAsCFString.get(), url)) { if (title) *title = url; success = true; } } GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } else if (SUCCEEDED(dataObject->GetData(filenameFormat(), &store))) { // filename using ascii char* data = static_cast(GlobalLock(store.hGlobal)); if (data && data[0] && (PathFileExistsA(data) || PathIsUNCA(data))) { RetainPtr pathAsCFString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, data, kCFStringEncodingASCII)); if (urlFromPath(pathAsCFString.get(), url)) { if (title) *title = url; success = true; } } GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } } #endif return url; } String getURL(const DragDataMap* data, DragData::FilenameConversionPolicy filenamePolicy, String* title) { String url; if (getWebLocData(data, url, title)) return url; if (getDataMapItem(data, urlWFormat(), url)) return extractURL(url, title); if (getDataMapItem(data, urlFormat(), url)) return extractURL(url, title); #if USE(CF) if (filenamePolicy != DragData::ConvertFilenames) return url; String stringData; if (!getDataMapItem(data, filenameWFormat(), stringData)) getDataMapItem(data, filenameFormat(), stringData); if (stringData.isEmpty() || (!PathFileExists(stringData.charactersWithNullTermination()) && !PathIsUNC(stringData.charactersWithNullTermination()))) return url; RetainPtr pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar *)stringData.charactersWithNullTermination(), wcslen(stringData.charactersWithNullTermination()))); if (urlFromPath(pathAsCFString.get(), url) && title) *title = url; #endif return url; } String getPlainText(IDataObject* dataObject, bool& success) { STGMEDIUM store; String text; success = false; if (SUCCEEDED(dataObject->GetData(plainTextWFormat(), &store))) { // Unicode text UChar* data = static_cast(GlobalLock(store.hGlobal)); text = String(data); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } else if (SUCCEEDED(dataObject->GetData(plainTextFormat(), &store))) { // ASCII text char* data = static_cast(GlobalLock(store.hGlobal)); text = String(data); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } else { // FIXME: Originally, we called getURL() here because dragging and dropping files doesn't // populate the drag with text data. Per https://bugs.webkit.org/show_bug.cgi?id=38826, this // is undesirable, so maybe this line can be removed. text = getURL(dataObject, DragData::DoNotConvertFilenames, success); success = true; } return text; } String getPlainText(const DragDataMap* data) { String text; if (getDataMapItem(data, plainTextWFormat(), text)) return text; if (getDataMapItem(data, plainTextFormat(), text)) return text; return getURL(data, DragData::DoNotConvertFilenames); } String getTextHTML(IDataObject* data, bool& success) { STGMEDIUM store; String html; success = false; if (SUCCEEDED(data->GetData(texthtmlFormat(), &store))) { UChar* data = static_cast(GlobalLock(store.hGlobal)); html = String(data); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); success = true; } return html; } String getTextHTML(const DragDataMap* data) { String text; getDataMapItem(data, texthtmlFormat(), text); return text; } String getCFHTML(IDataObject* data, bool& success) { String cfhtml = getFullCFHTML(data, success); if (success) return extractMarkupFromCFHTML(cfhtml); return String(); } String getCFHTML(const DragDataMap* dataMap) { String cfhtml; getDataMapItem(dataMap, htmlFormat(), cfhtml); return extractMarkupFromCFHTML(cfhtml); } PassRefPtr fragmentFromFilenames(Document*, const IDataObject*) { // FIXME: We should be able to create fragments from files return 0; } PassRefPtr fragmentFromFilenames(Document*, const DragDataMap*) { // FIXME: We should be able to create fragments from files return 0; } bool containsFilenames(const IDataObject*) { // FIXME: We'll want to update this once we can produce fragments from files return false; } bool containsFilenames(const DragDataMap*) { // FIXME: We'll want to update this once we can produce fragments from files return false; } // Convert a String containing CF_HTML formatted text to a DocumentFragment PassRefPtr fragmentFromCFHTML(Document* doc, const String& cfhtml) { // obtain baseURL if present String srcURLStr("sourceURL:"); String srcURL; unsigned lineStart = cfhtml.find(srcURLStr, 0, false); if (lineStart != -1) { unsigned srcEnd = cfhtml.find("\n", lineStart, false); unsigned srcStart = lineStart+srcURLStr.length(); String rawSrcURL = cfhtml.substring(srcStart, srcEnd-srcStart); replaceNBSPWithSpace(rawSrcURL); srcURL = rawSrcURL.stripWhiteSpace(); } String markup = extractMarkupFromCFHTML(cfhtml); return createFragmentFromMarkup(doc, markup, srcURL, FragmentScriptingNotAllowed); } PassRefPtr fragmentFromHTML(Document* doc, IDataObject* data) { if (!doc || !data) return 0; bool success = false; String cfhtml = getFullCFHTML(data, success); if (success) { if (RefPtr fragment = fragmentFromCFHTML(doc, cfhtml)) return fragment.release(); } String html = getTextHTML(data, success); String srcURL; if (success) return createFragmentFromMarkup(doc, html, srcURL, FragmentScriptingNotAllowed); return 0; } PassRefPtr fragmentFromHTML(Document* document, const DragDataMap* data) { if (!document || !data || data->isEmpty()) return 0; String stringData; if (getDataMapItem(data, htmlFormat(), stringData)) { if (RefPtr fragment = fragmentFromCFHTML(document, stringData)) return fragment.release(); } String srcURL; if (getDataMapItem(data, texthtmlFormat(), stringData)) return createFragmentFromMarkup(document, stringData, srcURL, FragmentScriptingNotAllowed); return 0; } bool containsHTML(IDataObject* data) { return SUCCEEDED(data->QueryGetData(texthtmlFormat())) || SUCCEEDED(data->QueryGetData(htmlFormat())); } bool containsHTML(const DragDataMap* data) { return data->contains(texthtmlFormat()->cfFormat) || data->contains(htmlFormat()->cfFormat); } typedef void (*GetStringFunction)(IDataObject*, FORMATETC*, Vector&); typedef void (*SetStringFunction)(IDataObject*, FORMATETC*, const Vector&); struct ClipboardDataItem { GetStringFunction getString; SetStringFunction setString; FORMATETC* format; ClipboardDataItem(FORMATETC* format, GetStringFunction getString, SetStringFunction setString): format(format), getString(getString), setString(setString) { } }; typedef HashMap ClipboardFormatMap; // Getter functions. template void getStringData(IDataObject* data, FORMATETC* format, Vector& dataStrings) { STGMEDIUM store; if (FAILED(data->GetData(format, &store))) return; dataStrings.append(String(static_cast(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T))); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } void getUtf8Data(IDataObject* data, FORMATETC* format, Vector& dataStrings) { STGMEDIUM store; if (FAILED(data->GetData(format, &store))) return; dataStrings.append(String(UTF8Encoding().decode(static_cast(GlobalLock(store.hGlobal)), GlobalSize(store.hGlobal)))); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } #if USE(CF) void getCFData(IDataObject* data, FORMATETC* format, Vector& dataStrings) { STGMEDIUM store; if (FAILED(data->GetData(format, &store))) return; HDROP hdrop = reinterpret_cast(GlobalLock(store.hGlobal)); if (!hdrop) return; WCHAR filename[MAX_PATH]; UINT fileCount = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0); for (UINT i = 0; i < fileCount; i++) { if (!DragQueryFileW(hdrop, i, filename, WTF_ARRAY_LENGTH(filename))) continue; dataStrings.append(static_cast(filename)); } GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } #endif // Setter functions. void setUCharData(IDataObject* data, FORMATETC* format, const Vector& dataStrings) { STGMEDIUM medium = {0}; medium.tymed = TYMED_HGLOBAL; medium.hGlobal = createGlobalData(dataStrings.first()); if (!medium.hGlobal) return; data->SetData(format, &medium, FALSE); ::GlobalFree(medium.hGlobal); } void setUtf8Data(IDataObject* data, FORMATETC* format, const Vector& dataStrings) { STGMEDIUM medium = {0}; medium.tymed = TYMED_HGLOBAL; CString charString = dataStrings.first().utf8(); size_t stringLength = charString.length(); medium.hGlobal = ::GlobalAlloc(GPTR, stringLength + 1); if (!medium.hGlobal) return; char* buffer = static_cast(GlobalLock(medium.hGlobal)); memcpy(buffer, charString.data(), stringLength); buffer[stringLength] = 0; GlobalUnlock(medium.hGlobal); data->SetData(format, &medium, FALSE); ::GlobalFree(medium.hGlobal); } #if USE(CF) void setCFData(IDataObject* data, FORMATETC* format, const Vector& dataStrings) { STGMEDIUM medium = {0}; SIZE_T dropFilesSize = sizeof(DROPFILES) + (sizeof(WCHAR) * (dataStrings.first().length() + 2)); medium.hGlobal = ::GlobalAlloc(GHND | GMEM_SHARE, dropFilesSize); if (!medium.hGlobal) return; DROPFILES* dropFiles = reinterpret_cast(GlobalLock(medium.hGlobal)); dropFiles->pFiles = sizeof(DROPFILES); dropFiles->fWide = TRUE; String filename = dataStrings.first(); wcscpy(reinterpret_cast(dropFiles + 1), filename.charactersWithNullTermination()); GlobalUnlock(medium.hGlobal); data->SetData(format, &medium, FALSE); ::GlobalFree(medium.hGlobal); } #endif static const ClipboardFormatMap& getClipboardMap() { static ClipboardFormatMap formatMap; if (formatMap.isEmpty()) { formatMap.add(htmlFormat()->cfFormat, new ClipboardDataItem(htmlFormat(), getUtf8Data, setUtf8Data)); formatMap.add(texthtmlFormat()->cfFormat, new ClipboardDataItem(texthtmlFormat(), getStringData, setUCharData)); formatMap.add(plainTextFormat()->cfFormat, new ClipboardDataItem(plainTextFormat(), getStringData, setUtf8Data)); formatMap.add(plainTextWFormat()->cfFormat, new ClipboardDataItem(plainTextWFormat(), getStringData, setUCharData)); #if USE(CF) formatMap.add(cfHDropFormat()->cfFormat, new ClipboardDataItem(cfHDropFormat(), getCFData, setCFData)); #endif formatMap.add(filenameFormat()->cfFormat, new ClipboardDataItem(filenameFormat(), getStringData, setUtf8Data)); formatMap.add(filenameWFormat()->cfFormat, new ClipboardDataItem(filenameWFormat(), getStringData, setUCharData)); formatMap.add(urlFormat()->cfFormat, new ClipboardDataItem(urlFormat(), getStringData, setUtf8Data)); formatMap.add(urlWFormat()->cfFormat, new ClipboardDataItem(urlWFormat(), getStringData, setUCharData)); } return formatMap; } void getClipboardData(IDataObject* dataObject, FORMATETC* format, Vector& dataStrings) { const ClipboardFormatMap& formatMap = getClipboardMap(); ClipboardFormatMap::const_iterator found = formatMap.find(format->cfFormat); if (found == formatMap.end()) return; found->second->getString(dataObject, found->second->format, dataStrings); } void setClipboardData(IDataObject* dataObject, UINT format, const Vector& dataStrings) { const ClipboardFormatMap& formatMap = getClipboardMap(); ClipboardFormatMap::const_iterator found = formatMap.find(format); if (found == formatMap.end()) return; found->second->setString(dataObject, found->second->format, dataStrings); } } // namespace WebCore