diff --git a/src/common/dobjcmn.cpp b/src/common/dobjcmn.cpp index df53042af8..04d058dbf2 100644 --- a/src/common/dobjcmn.cpp +++ b/src/common/dobjcmn.cpp @@ -429,6 +429,141 @@ bool wxTextDataObject::SetData(size_t len, const void *buf) // wxHTMLDataObject // ---------------------------------------------------------------------------- +#ifdef __WXMSW__ + +// Helper functions for MSW CF_HTML format, see MSDN for more information: +// +// https://learn.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format +namespace wxMSWClip +{ + +const char* const VERSION_HEADER = "Version:"; +const size_t VERSION_HEADER_LEN = strlen(VERSION_HEADER); + +const char* const START_HTML_HEADER = "StartHTML:"; +const size_t START_HTML_HEADER_LEN = strlen(START_HTML_HEADER); + +const char* const END_HTML_HEADER = "EndHTML:"; +const size_t END_HTML_HEADER_LEN = strlen(END_HTML_HEADER); + +const char* const START_FRAGMENT_HEADER = "StartFragment:"; +const size_t START_FRAGMENT_HEADER_LEN = strlen(START_FRAGMENT_HEADER); + +const char* const END_FRAGMENT_HEADER = "EndFragment:"; +const size_t END_FRAGMENT_HEADER_LEN = strlen(END_FRAGMENT_HEADER); + +const char* const CF_HTML_PREAMBLE = + "Version:0.9\r\n" + "StartHTML:00000000\r\n" + "EndHTML:00000000\r\n" + "StartFragment:00000000\r\n" + "EndFragment:00000000\r\n" + ; +const size_t CF_HTML_PREAMBLE_LEN = strlen(CF_HTML_PREAMBLE); + +const char* const CF_HTML_WRAP_START = + "\r\n" + "" + ; +const size_t CF_HTML_WRAP_START_LEN = strlen(CF_HTML_WRAP_START); + +const char* const CF_HTML_WRAP_END = + "\r\n" + "\r\n" + "" + ; +const size_t CF_HTML_WRAP_END_LEN = strlen(CF_HTML_WRAP_END); + + +// Return the extra size needed by HTML data in addition to the length of the +// HTML fragment itself. +int GetExtraDataSize() +{ + // +1 is for the trailing NUL. + return CF_HTML_PREAMBLE_LEN + CF_HTML_WRAP_START_LEN + CF_HTML_WRAP_END_LEN + 1; +} + +// Wrap HTML data with the extra information needed by CF_HTML and copy +// everything into the provided buffer assumed to be of sufficient size. +void FillFromHTML(char* buffer, const char* html, size_t lenHTML) +{ + // add the extra info that the MSW clipboard format requires. + + // Create a template string for the HTML header... + strcpy(buffer, CF_HTML_PREAMBLE); + const size_t startHTML = CF_HTML_PREAMBLE_LEN; + + strcat(buffer, CF_HTML_WRAP_START); + const size_t startFragment = startHTML + CF_HTML_WRAP_START_LEN; + + // Append the HTML... + strncat(buffer, html, lenHTML); + const size_t endFragment = startFragment + lenHTML; + + // Finish up the HTML format... + strcat(buffer, CF_HTML_WRAP_END); + const size_t endHTML = endFragment + CF_HTML_WRAP_END_LEN; + + // Now go back and write out the necessary header information. + // + // Note, wsprintf() truncates the string when you overwrite it so you + // follow up with code to replace the 0 appended at the end with a '\r'. + const size_t OFFSET_LEN = 8; // All offsets are formatted using 8 digits. + + char *ptr = strstr(buffer, START_HTML_HEADER); + sprintf(ptr+START_HTML_HEADER_LEN, "%08zu", startHTML); + *(ptr+START_HTML_HEADER_LEN+OFFSET_LEN) = '\r'; + + ptr = strstr(buffer, END_HTML_HEADER); + sprintf(ptr+END_HTML_HEADER_LEN, "%08zu", endHTML); + *(ptr+END_HTML_HEADER_LEN+OFFSET_LEN) = '\r'; + + ptr = strstr(buffer, START_FRAGMENT_HEADER); + sprintf(ptr+START_FRAGMENT_HEADER_LEN, "%08zu", startFragment); + *(ptr+START_FRAGMENT_HEADER_LEN+OFFSET_LEN) = '\r'; + + ptr = strstr(buffer, END_FRAGMENT_HEADER); + sprintf(ptr+END_FRAGMENT_HEADER_LEN, "%08zu", endFragment); + *(ptr+END_FRAGMENT_HEADER_LEN+OFFSET_LEN) = '\r'; +} + +// Extract just the HTML fragment part from CF_HTML data. +wxString ExtractHTML(const char* buffer, size_t len) +{ + // Sanity check. + if ( len < VERSION_HEADER_LEN || + wxCRT_StrnicmpA(buffer, VERSION_HEADER, VERSION_HEADER_LEN) != 0 ) + { + // This doesn't look like CF_HTML at all, don't do anything. + return wxString(); + } + + const char* ptr = strstr(buffer, START_FRAGMENT_HEADER); + if ( !ptr ) + return wxString(); + + ptr += START_FRAGMENT_HEADER_LEN; + + const int start = atoi(ptr); + if ( start < 0 || (unsigned)start >= len ) + return wxString(); + + ptr = strstr(ptr, END_FRAGMENT_HEADER); + if ( !ptr ) + return wxString(); + + ptr += END_FRAGMENT_HEADER_LEN; + const int end = atoi(ptr); + if ( end < 0 || end < start || (unsigned)end >= len ) + return wxString(); + + return wxString::FromUTF8(buffer + start, end - start); +} + +} // anonymous namespace + +#endif // __WXMSW__ + size_t wxHTMLDataObject::GetDataSize() const { // Ensure that the temporary string returned by GetHTML() is kept alive for @@ -439,9 +574,7 @@ size_t wxHTMLDataObject::GetDataSize() const size_t size = buffer.length(); #ifdef __WXMSW__ - // On Windows we need to add some stuff to the string to satisfy - // its clipboard format requirements. - size += 400; + size += wxMSWClip::GetExtraDataSize(); #endif return size; @@ -461,75 +594,27 @@ bool wxHTMLDataObject::GetDataHere(void *buf) const char* const buffer = static_cast(buf); #ifdef __WXMSW__ - // add the extra info that the MSW clipboard format requires. - - // Create a template string for the HTML header... - strcpy(buffer, - "Version:0.9\r\n" - "StartHTML:00000000\r\n" - "EndHTML:00000000\r\n" - "StartFragment:00000000\r\n" - "EndFragment:00000000\r\n" - "\r\n" - "\r\n"); - - // Append the HTML... - strcat(buffer, html); - strcat(buffer, "\r\n"); - // Finish up the HTML format... - strcat(buffer, - "\r\n" - "\r\n" - ""); - - // Now go back, calculate all the lengths, and write out the - // necessary header information. Note, wsprintf() truncates the - // string when you overwrite it so you follow up with code to replace - // the 0 appended at the end with a '\r'... - char *ptr = strstr(buffer, "StartHTML"); - sprintf(ptr+10, "%08u", (unsigned)(strstr(buffer, "") - buffer)); - *(ptr+10+8) = '\r'; - - ptr = strstr(buffer, "EndHTML"); - sprintf(ptr+8, "%08u", (unsigned)strlen(buffer)); - *(ptr+8+8) = '\r'; - - ptr = strstr(buffer, "StartFragment"); - sprintf(ptr+14, "%08u", (unsigned)(strstr(buffer, "", fragmentStart) + 3; - int endCommentStart = html.rfind("