| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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 | |
| 5 #include "base/clipboard_util.h" | |
| 6 | |
| 7 #include <shellapi.h> | |
| 8 #include <shlwapi.h> | |
| 9 #include <wininet.h> | |
| 10 | |
| 11 #include "base/basictypes.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/scoped_handle.h" | |
| 14 #include "base/string_util.h" | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 bool GetUrlFromHDrop(IDataObject* data_object, std::wstring* url, | |
| 19 std::wstring* title) { | |
| 20 DCHECK(data_object && url && title); | |
| 21 | |
| 22 STGMEDIUM medium; | |
| 23 if (FAILED(data_object->GetData(ClipboardUtil::GetCFHDropFormat(), &medium))) | |
| 24 return false; | |
| 25 | |
| 26 HDROP hdrop = static_cast<HDROP>(GlobalLock(medium.hGlobal)); | |
| 27 | |
| 28 if (!hdrop) | |
| 29 return false; | |
| 30 | |
| 31 bool success = false; | |
| 32 wchar_t filename[MAX_PATH]; | |
| 33 if (DragQueryFileW(hdrop, 0, filename, arraysize(filename))) { | |
| 34 wchar_t url_buffer[INTERNET_MAX_URL_LENGTH]; | |
| 35 if (0 == _wcsicmp(PathFindExtensionW(filename), L".url") && | |
| 36 GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, url_buffer, | |
| 37 arraysize(url_buffer), filename)) { | |
| 38 *url = url_buffer; | |
| 39 PathRemoveExtension(filename); | |
| 40 title->assign(PathFindFileName(filename)); | |
| 41 success = true; | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 DragFinish(hdrop); | |
| 46 GlobalUnlock(medium.hGlobal); | |
| 47 // We don't need to call ReleaseStgMedium here because as far as I can tell, | |
| 48 // DragFinish frees the hGlobal for us. | |
| 49 return success; | |
| 50 } | |
| 51 | |
| 52 bool SplitUrlAndTitle(const std::wstring& str, std::wstring* url, | |
| 53 std::wstring* title) { | |
| 54 DCHECK(url && title); | |
| 55 size_t newline_pos = str.find('\n'); | |
| 56 bool success = false; | |
| 57 if (newline_pos != std::string::npos) { | |
| 58 *url = str.substr(0, newline_pos); | |
| 59 title->assign(str.substr(newline_pos + 1)); | |
| 60 success = true; | |
| 61 } else { | |
| 62 *url = str; | |
| 63 title->assign(str); | |
| 64 success = true; | |
| 65 } | |
| 66 return success; | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 71 | |
| 72 FORMATETC* ClipboardUtil::GetUrlFormat() { | |
| 73 static UINT cf = RegisterClipboardFormat(CFSTR_INETURLA); | |
| 74 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 75 return &format; | |
| 76 } | |
| 77 | |
| 78 FORMATETC* ClipboardUtil::GetUrlWFormat() { | |
| 79 static UINT cf = RegisterClipboardFormat(CFSTR_INETURLW); | |
| 80 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 81 return &format; | |
| 82 } | |
| 83 | |
| 84 FORMATETC* ClipboardUtil::GetMozUrlFormat() { | |
| 85 // The format is "URL\nTitle" | |
| 86 static UINT cf = RegisterClipboardFormat(L"text/x-moz-url"); | |
| 87 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 88 return &format; | |
| 89 } | |
| 90 | |
| 91 FORMATETC* ClipboardUtil::GetPlainTextFormat() { | |
| 92 // We don't need to register this format since it's a built in format. | |
| 93 static FORMATETC format = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 94 return &format; | |
| 95 } | |
| 96 | |
| 97 FORMATETC* ClipboardUtil::GetPlainTextWFormat() { | |
| 98 // We don't need to register this format since it's a built in format. | |
| 99 static FORMATETC format = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, | |
| 100 TYMED_HGLOBAL}; | |
| 101 return &format; | |
| 102 } | |
| 103 | |
| 104 FORMATETC* ClipboardUtil::GetFilenameWFormat() { | |
| 105 static UINT cf = RegisterClipboardFormat(CFSTR_FILENAMEW); | |
| 106 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 107 return &format; | |
| 108 } | |
| 109 | |
| 110 FORMATETC* ClipboardUtil::GetFilenameFormat() { | |
| 111 static UINT cf = RegisterClipboardFormat(CFSTR_FILENAMEA); | |
| 112 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 113 return &format; | |
| 114 } | |
| 115 | |
| 116 FORMATETC* ClipboardUtil::GetHtmlFormat() { | |
| 117 static UINT cf = RegisterClipboardFormat(L"HTML Format"); | |
| 118 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 119 return &format; | |
| 120 } | |
| 121 | |
| 122 FORMATETC* ClipboardUtil::GetTextHtmlFormat() { | |
| 123 static UINT cf = RegisterClipboardFormat(L"text/html"); | |
| 124 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 125 return &format; | |
| 126 } | |
| 127 | |
| 128 FORMATETC* ClipboardUtil::GetCFHDropFormat() { | |
| 129 // We don't need to register this format since it's a built in format. | |
| 130 static FORMATETC format = {CF_HDROP, 0, DVASPECT_CONTENT, -1, | |
| 131 TYMED_HGLOBAL}; | |
| 132 return &format; | |
| 133 } | |
| 134 | |
| 135 FORMATETC* ClipboardUtil::GetFileDescriptorFormat() { | |
| 136 static UINT cf = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR); | |
| 137 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; | |
| 138 return &format; | |
| 139 } | |
| 140 | |
| 141 FORMATETC* ClipboardUtil::GetFileContentFormatZero() { | |
| 142 static UINT cf = RegisterClipboardFormat(CFSTR_FILECONTENTS); | |
| 143 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL}; | |
| 144 return &format; | |
| 145 } | |
| 146 | |
| 147 FORMATETC* ClipboardUtil::GetWebKitSmartPasteFormat() { | |
| 148 static UINT cf = RegisterClipboardFormat(L"WebKit Smart Paste Format"); | |
| 149 static FORMATETC format = {cf, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL}; | |
| 150 return &format; | |
| 151 } | |
| 152 | |
| 153 | |
| 154 bool ClipboardUtil::HasUrl(IDataObject* data_object) { | |
| 155 DCHECK(data_object); | |
| 156 return SUCCEEDED(data_object->QueryGetData(GetMozUrlFormat())) || | |
| 157 SUCCEEDED(data_object->QueryGetData(GetUrlWFormat())) || | |
| 158 SUCCEEDED(data_object->QueryGetData(GetUrlFormat())) || | |
| 159 SUCCEEDED(data_object->QueryGetData(GetFilenameWFormat())) || | |
| 160 SUCCEEDED(data_object->QueryGetData(GetFilenameFormat())); | |
| 161 } | |
| 162 | |
| 163 bool ClipboardUtil::HasFilenames(IDataObject* data_object) { | |
| 164 DCHECK(data_object); | |
| 165 return SUCCEEDED(data_object->QueryGetData(GetCFHDropFormat())); | |
| 166 } | |
| 167 | |
| 168 bool ClipboardUtil::HasFileContents(IDataObject* data_object) { | |
| 169 DCHECK(data_object); | |
| 170 return SUCCEEDED(data_object->QueryGetData(GetFileContentFormatZero())); | |
| 171 } | |
| 172 | |
| 173 bool ClipboardUtil::HasHtml(IDataObject* data_object) { | |
| 174 DCHECK(data_object); | |
| 175 return SUCCEEDED(data_object->QueryGetData(GetHtmlFormat())) || | |
| 176 SUCCEEDED(data_object->QueryGetData(GetTextHtmlFormat())); | |
| 177 } | |
| 178 | |
| 179 bool ClipboardUtil::HasPlainText(IDataObject* data_object) { | |
| 180 DCHECK(data_object); | |
| 181 return SUCCEEDED(data_object->QueryGetData(GetPlainTextWFormat())) || | |
| 182 SUCCEEDED(data_object->QueryGetData(GetPlainTextFormat())); | |
| 183 } | |
| 184 | |
| 185 | |
| 186 bool ClipboardUtil::GetUrl(IDataObject* data_object, | |
| 187 std::wstring* url, std::wstring* title) { | |
| 188 DCHECK(data_object && url && title); | |
| 189 if (!HasUrl(data_object)) | |
| 190 return false; | |
| 191 | |
| 192 // Try to extract a URL from |data_object| in a variety of formats. | |
| 193 STGMEDIUM store; | |
| 194 if (GetUrlFromHDrop(data_object, url, title)) { | |
| 195 return true; | |
| 196 } | |
| 197 | |
| 198 if (SUCCEEDED(data_object->GetData(GetMozUrlFormat(), &store)) || | |
| 199 SUCCEEDED(data_object->GetData(GetUrlWFormat(), &store))) { | |
| 200 // Mozilla URL format or unicode URL | |
| 201 ScopedHGlobal<wchar_t> data(store.hGlobal); | |
| 202 bool success = SplitUrlAndTitle(data.get(), url, title); | |
| 203 ReleaseStgMedium(&store); | |
| 204 if (success) | |
| 205 return true; | |
| 206 } | |
| 207 | |
| 208 if (SUCCEEDED(data_object->GetData(GetUrlFormat(), &store))) { | |
| 209 // URL using ascii | |
| 210 ScopedHGlobal<char> data(store.hGlobal); | |
| 211 bool success = SplitUrlAndTitle(UTF8ToWide(data.get()), url, title); | |
| 212 ReleaseStgMedium(&store); | |
| 213 if (success) | |
| 214 return true; | |
| 215 } | |
| 216 | |
| 217 if (SUCCEEDED(data_object->GetData(GetFilenameWFormat(), &store))) { | |
| 218 // filename using unicode | |
| 219 ScopedHGlobal<wchar_t> data(store.hGlobal); | |
| 220 bool success = false; | |
| 221 if (data.get() && data.get()[0] && (PathFileExists(data.get()) || | |
| 222 PathIsUNC(data.get()))) { | |
| 223 wchar_t file_url[INTERNET_MAX_URL_LENGTH]; | |
| 224 DWORD file_url_len = sizeof(file_url) / sizeof(file_url[0]); | |
| 225 if (SUCCEEDED(::UrlCreateFromPathW(data.get(), file_url, &file_url_len, | |
| 226 0))) { | |
| 227 *url = file_url; | |
| 228 title->assign(file_url); | |
| 229 success = true; | |
| 230 } | |
| 231 } | |
| 232 ReleaseStgMedium(&store); | |
| 233 if (success) | |
| 234 return true; | |
| 235 } | |
| 236 | |
| 237 if (SUCCEEDED(data_object->GetData(GetFilenameFormat(), &store))) { | |
| 238 // filename using ascii | |
| 239 ScopedHGlobal<char> data(store.hGlobal); | |
| 240 bool success = false; | |
| 241 if (data.get() && data.get()[0] && (PathFileExistsA(data.get()) || | |
| 242 PathIsUNCA(data.get()))) { | |
| 243 char file_url[INTERNET_MAX_URL_LENGTH]; | |
| 244 DWORD file_url_len = sizeof(file_url) / sizeof(file_url[0]); | |
| 245 if (SUCCEEDED(::UrlCreateFromPathA(data.get(), | |
| 246 file_url, | |
| 247 &file_url_len, | |
| 248 0))) { | |
| 249 *url = UTF8ToWide(file_url); | |
| 250 title->assign(*url); | |
| 251 success = true; | |
| 252 } | |
| 253 } | |
| 254 ReleaseStgMedium(&store); | |
| 255 if (success) | |
| 256 return true; | |
| 257 } | |
| 258 | |
| 259 return false; | |
| 260 } | |
| 261 | |
| 262 bool ClipboardUtil::GetFilenames(IDataObject* data_object, | |
| 263 std::vector<std::wstring>* filenames) { | |
| 264 DCHECK(data_object && filenames); | |
| 265 if (!HasFilenames(data_object)) | |
| 266 return false; | |
| 267 | |
| 268 STGMEDIUM medium; | |
| 269 if (FAILED(data_object->GetData(GetCFHDropFormat(), &medium))) | |
| 270 return false; | |
| 271 | |
| 272 HDROP hdrop = static_cast<HDROP>(GlobalLock(medium.hGlobal)); | |
| 273 if (!hdrop) | |
| 274 return false; | |
| 275 | |
| 276 const int kMaxFilenameLen = 4096; | |
| 277 const unsigned num_files = DragQueryFileW(hdrop, 0xffffffff, 0, 0); | |
| 278 for (unsigned int i = 0; i < num_files; ++i) { | |
| 279 wchar_t filename[kMaxFilenameLen]; | |
| 280 if (!DragQueryFileW(hdrop, i, filename, kMaxFilenameLen)) | |
| 281 continue; | |
| 282 filenames->push_back(filename); | |
| 283 } | |
| 284 | |
| 285 DragFinish(hdrop); | |
| 286 GlobalUnlock(medium.hGlobal); | |
| 287 // We don't need to call ReleaseStgMedium here because as far as I can tell, | |
| 288 // DragFinish frees the hGlobal for us. | |
| 289 return true; | |
| 290 } | |
| 291 | |
| 292 bool ClipboardUtil::GetPlainText(IDataObject* data_object, | |
| 293 std::wstring* plain_text) { | |
| 294 DCHECK(data_object && plain_text); | |
| 295 if (!HasPlainText(data_object)) | |
| 296 return false; | |
| 297 | |
| 298 STGMEDIUM store; | |
| 299 bool success = false; | |
| 300 if (SUCCEEDED(data_object->GetData(GetPlainTextWFormat(), &store))) { | |
| 301 // Unicode text | |
| 302 ScopedHGlobal<wchar_t> data(store.hGlobal); | |
| 303 plain_text->assign(data.get()); | |
| 304 ReleaseStgMedium(&store); | |
| 305 success = true; | |
| 306 } else if (SUCCEEDED(data_object->GetData(GetPlainTextFormat(), &store))) { | |
| 307 // ascii text | |
| 308 ScopedHGlobal<char> data(store.hGlobal); | |
| 309 plain_text->assign(UTF8ToWide(data.get())); | |
| 310 ReleaseStgMedium(&store); | |
| 311 success = true; | |
| 312 } else { | |
| 313 // If a file is dropped on the window, it does not provide either of the | |
| 314 // plain text formats, so here we try to forcibly get a url. | |
| 315 std::wstring title; | |
| 316 success = GetUrl(data_object, plain_text, &title); | |
| 317 } | |
| 318 | |
| 319 return success; | |
| 320 } | |
| 321 | |
| 322 bool ClipboardUtil::GetHtml(IDataObject* data_object, | |
| 323 std::wstring* html, std::string* base_url) { | |
| 324 DCHECK(data_object && html && base_url); | |
| 325 | |
| 326 if (SUCCEEDED(data_object->QueryGetData(GetHtmlFormat()))) { | |
| 327 STGMEDIUM store; | |
| 328 if (SUCCEEDED(data_object->GetData(GetHtmlFormat(), &store))) { | |
| 329 // MS CF html | |
| 330 ScopedHGlobal<char> data(store.hGlobal); | |
| 331 | |
| 332 std::string html_utf8; | |
| 333 CFHtmlToHtml(std::string(data.get(), data.Size()), &html_utf8, base_url); | |
| 334 html->assign(UTF8ToWide(html_utf8)); | |
| 335 | |
| 336 ReleaseStgMedium(&store); | |
| 337 return true; | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 if (FAILED(data_object->QueryGetData(GetTextHtmlFormat()))) | |
| 342 return false; | |
| 343 | |
| 344 STGMEDIUM store; | |
| 345 if (FAILED(data_object->GetData(GetTextHtmlFormat(), &store))) | |
| 346 return false; | |
| 347 | |
| 348 // text/html | |
| 349 ScopedHGlobal<wchar_t> data(store.hGlobal); | |
| 350 html->assign(data.get()); | |
| 351 ReleaseStgMedium(&store); | |
| 352 return true; | |
| 353 } | |
| 354 | |
| 355 bool ClipboardUtil::GetFileContents(IDataObject* data_object, | |
| 356 std::wstring* filename, std::string* file_contents) { | |
| 357 DCHECK(data_object && filename && file_contents); | |
| 358 bool has_data = | |
| 359 SUCCEEDED(data_object->QueryGetData(GetFileContentFormatZero())) || | |
| 360 SUCCEEDED(data_object->QueryGetData(GetFileDescriptorFormat())); | |
| 361 | |
| 362 if (!has_data) | |
| 363 return false; | |
| 364 | |
| 365 STGMEDIUM content; | |
| 366 // The call to GetData can be very slow depending on what is in | |
| 367 // |data_object|. | |
| 368 if (SUCCEEDED(data_object->GetData(GetFileContentFormatZero(), &content))) { | |
| 369 if (TYMED_HGLOBAL == content.tymed) { | |
| 370 ScopedHGlobal<char> data(content.hGlobal); | |
| 371 file_contents->assign(data.get(), data.Size()); | |
| 372 } | |
| 373 ReleaseStgMedium(&content); | |
| 374 } | |
| 375 | |
| 376 STGMEDIUM description; | |
| 377 if (SUCCEEDED(data_object->GetData(GetFileDescriptorFormat(), | |
| 378 &description))) { | |
| 379 ScopedHGlobal<FILEGROUPDESCRIPTOR> fgd(description.hGlobal); | |
| 380 // We expect there to be at least one file in here. | |
| 381 DCHECK_GE(fgd->cItems, 1); | |
| 382 filename->assign(fgd->fgd[0].cFileName); | |
| 383 ReleaseStgMedium(&description); | |
| 384 } | |
| 385 return true; | |
| 386 } | |
| 387 | |
| 388 // HtmlToCFHtml and CFHtmlToHtml are based on similar methods in | |
| 389 // WebCore/platform/win/ClipboardUtilitiesWin.cpp. | |
| 390 /* | |
| 391 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | |
| 392 * | |
| 393 * Redistribution and use in source and binary forms, with or without | |
| 394 * modification, are permitted provided that the following conditions | |
| 395 * are met: | |
| 396 * 1. Redistributions of source code must retain the above copyright | |
| 397 * notice, this list of conditions and the following disclaimer. | |
| 398 * 2. Redistributions in binary form must reproduce the above copyright | |
| 399 * notice, this list of conditions and the following disclaimer in the | |
| 400 * documentation and/or other materials provided with the distribution. | |
| 401 * | |
| 402 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
| 403 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 404 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 405 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
| 406 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 407 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 408 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 409 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 410 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 411 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 412 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 413 */ | |
| 414 | |
| 415 // Helper method for converting from text/html to MS CF_HTML. | |
| 416 // Documentation for the CF_HTML format is available at | |
| 417 // http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx | |
| 418 std::string ClipboardUtil::HtmlToCFHtml(const std::string& html, | |
| 419 const std::string& base_url) { | |
| 420 if (html.empty()) | |
| 421 return std::string(); | |
| 422 | |
| 423 #define MAX_DIGITS 10 | |
| 424 #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits) | |
| 425 #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u" | |
| 426 #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS) | |
| 427 | |
| 428 static const char* header = "Version:0.9\r\n" | |
| 429 "StartHTML:" NUMBER_FORMAT "\r\n" | |
| 430 "EndHTML:" NUMBER_FORMAT "\r\n" | |
| 431 "StartFragment:" NUMBER_FORMAT "\r\n" | |
| 432 "EndFragment:" NUMBER_FORMAT "\r\n"; | |
| 433 static const char* source_url_prefix = "SourceURL:"; | |
| 434 | |
| 435 static const char* start_markup = | |
| 436 "<html>\r\n<body>\r\n<!--StartFragment-->\r\n"; | |
| 437 static const char* end_markup = | |
| 438 "\r\n<!--EndFragment-->\r\n</body>\r\n</html>"; | |
| 439 | |
| 440 // Calculate offsets | |
| 441 size_t start_html_offset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + | |
| 442 MAX_DIGITS * 4; | |
| 443 if (!base_url.empty()) { | |
| 444 start_html_offset += strlen(source_url_prefix) + | |
| 445 base_url.length() + 2; // Add 2 for \r\n. | |
| 446 } | |
| 447 size_t start_fragment_offset = start_html_offset + strlen(start_markup); | |
| 448 size_t end_fragment_offset = start_fragment_offset + html.length(); | |
| 449 size_t end_html_offset = end_fragment_offset + strlen(end_markup); | |
| 450 | |
| 451 std::string result = StringPrintf(header, start_html_offset, | |
| 452 end_html_offset, start_fragment_offset, end_fragment_offset); | |
| 453 if (!base_url.empty()) { | |
| 454 result.append(source_url_prefix); | |
| 455 result.append(base_url); | |
| 456 result.append("\r\n"); | |
| 457 } | |
| 458 result.append(start_markup); | |
| 459 result.append(html); | |
| 460 result.append(end_markup); | |
| 461 | |
| 462 #undef MAX_DIGITS | |
| 463 #undef MAKE_NUMBER_FORMAT_1 | |
| 464 #undef MAKE_NUMBER_FORMAT_2 | |
| 465 #undef NUMBER_FORMAT | |
| 466 | |
| 467 return result; | |
| 468 } | |
| 469 | |
| 470 // Helper method for converting from MS CF_HTML to text/html. | |
| 471 void ClipboardUtil::CFHtmlToHtml(const std::string& cf_html, | |
| 472 std::string* html, | |
| 473 std::string* base_url) { | |
| 474 // Obtain base_url if present. | |
| 475 if (base_url) { | |
| 476 static std::string src_url_str("SourceURL:"); | |
| 477 size_t line_start = cf_html.find(src_url_str); | |
| 478 if (line_start != std::string::npos) { | |
| 479 size_t src_end = cf_html.find("\n", line_start); | |
| 480 size_t src_start = line_start + src_url_str.length(); | |
| 481 if (src_end != std::string::npos && src_start != std::string::npos) { | |
| 482 *base_url = cf_html.substr(src_start, src_end - src_start); | |
| 483 TrimWhitespace(*base_url, TRIM_ALL, base_url); | |
| 484 } | |
| 485 } | |
| 486 } | |
| 487 | |
| 488 // Find the markup between "<!--StartFragment -->" and "<!--EndFragment-->". | |
| 489 if (html) { | |
| 490 std::string cf_html_lower = StringToLowerASCII(cf_html); | |
| 491 size_t markup_start = cf_html_lower.find("<html", 0); | |
| 492 size_t tag_start = cf_html.find("StartFragment", markup_start); | |
| 493 size_t fragment_start = cf_html.find('>', tag_start) + 1; | |
| 494 size_t tag_end = cf_html.rfind("EndFragment", std::string::npos); | |
| 495 size_t fragment_end = cf_html.rfind('<', tag_end); | |
| 496 if (fragment_start != std::string::npos && | |
| 497 fragment_end != std::string::npos) { | |
| 498 *html = cf_html.substr(fragment_start, fragment_end - fragment_start); | |
| 499 TrimWhitespace(*html, TRIM_ALL, html); | |
| 500 } | |
| 501 } | |
| 502 } | |
| OLD | NEW |