From 3ba174b7c84af46ac641a4fb87b861c9adf4bf83 Mon Sep 17 00:00:00 2001 From: "pinkerton%netscape.com" Date: Tue, 7 May 2002 19:45:58 +0000 Subject: [PATCH] Make CF_HTML a different flavor and return it to editor w/out any modification. Bulletproof the data we get from the OS by always null terminating it. r=brade/sr=kin bug# 69566. --- widget/public/nsITransferable.idl | 1 + widget/src/windows/nsClipboard.cpp | 88 ++++++++++++--------- widget/src/windows/nsClipboard.h | 1 + widget/src/xpwidgets/nsPrimitiveHelpers.cpp | 6 +- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/widget/public/nsITransferable.idl b/widget/public/nsITransferable.idl index ccc7e449560a..ed27ddc34d0a 100644 --- a/widget/public/nsITransferable.idl +++ b/widget/public/nsITransferable.idl @@ -39,6 +39,7 @@ #define kFileMime "application/x-moz-file" #define kURLMime "text/x-moz-url" #define kNativeImageMime "application/x-moz-nativeimage" +#define kNativeHTMLMime "application/x-moz-nativehtml" %} diff --git a/widget/src/windows/nsClipboard.cpp b/widget/src/windows/nsClipboard.cpp index 87c25259aaab..eaa40e396192 100644 --- a/widget/src/windows/nsClipboard.cpp +++ b/widget/src/windows/nsClipboard.cpp @@ -105,8 +105,8 @@ UINT nsClipboard::GetFormat(const char* aMimeStr) format = CF_HDROP; else if (mimeStr.Equals(kURLMime)) format = CF_UNICODETEXT; - else if (mimeStr.Equals(kHTMLMime)) - format = nsClipboard::CF_HTML; + else if (mimeStr.Equals(kNativeHTMLMime)) + format = CF_HTML; else format = ::RegisterClipboardFormat(aMimeStr); @@ -249,18 +249,22 @@ NS_IMETHODIMP nsClipboard::SetNativeClipboardData ( PRInt32 aWhichClipboard ) nsresult nsClipboard::GetGlobalData(HGLOBAL aHGBL, void ** aData, PRUint32 * aLen) { // Allocate a new memory buffer and copy the data from global memory. - // Recall that win98 allocates to nearest DWORD boundary. + // Recall that win98 allocates to nearest DWORD boundary. As a safety + // precaution, allocate an extra 2 bytes (but don't report them!) and + // null them out to ensure that all of our strlen calls will succeed. nsresult result = NS_ERROR_FAILURE; if (aHGBL != NULL) { LPSTR lpStr = (LPSTR)::GlobalLock(aHGBL); DWORD allocSize = ::GlobalSize(aHGBL); - char* data = NS_STATIC_CAST(char*, nsMemory::Alloc(allocSize)); + char* data = NS_STATIC_CAST(char*, nsMemory::Alloc(allocSize + sizeof(PRUnichar))); if ( data ) { - memcpy ( data, lpStr, allocSize ); - + memcpy ( data, lpStr, allocSize ); + data[allocSize] = data[allocSize + 1] = '\0'; // null terminate for safety + ::GlobalUnlock(aHGBL); *aData = data; *aLen = allocSize; + result = NS_OK; } } @@ -487,11 +491,10 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT if ( NS_SUCCEEDED(GetGlobalData(stm.hGlobal, aData, &allocLen)) ) { if ( fe.cfFormat == CF_HTML ) { // CF_HTML is actually UTF8, not unicode, so disregard the assumption - // above. We have to keep the null termination because of bugs in - // nsDependentCString (141866). The string will be stripped of its null by - // conversion to unicode in GetDataFromDataObject(), so it'll all - // end up well. - *aLen = strlen ( NS_REINTERPRET_CAST(char*, *aData) ) + sizeof(char); + // above. We have to check the header for the actual length, and we'll + // do that in FindPlatformHTML(). For now, return the allocLen. This + // case is mostly to ensure we don't try to call strlen on the buffer. + *aLen = allocLen; } else *aLen = nsCRT::strlen(NS_REINTERPRET_CAST(PRUnichar*, *aData)) * sizeof(PRUnichar); @@ -586,32 +589,16 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, if ( NS_SUCCEEDED(NS_NewNativeLocalFile(filepath, PR_FALSE, getter_AddRefs(file))) ) genericDataWrapper = do_QueryInterface(file); } - else if ( strcmp(flavorStr, kHTMLMime) == 0 ) { - // CF_HTML is different from what we want as html. Munge the data appropriately. - - // convert the win32 line endings to DOM line endings. We do this first to - // avoid another copy since we can't replace the converter's buffer in situ. - // CF_HTML is UTF8, so tell the converter we have text/plain so that it does - // single byte conversion. - PRInt32 signedLen = NS_STATIC_CAST(PRInt32, dataLen); - nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks ( kTextMime, &data, &signedLen ); - - // Convert from CF_HTML to gecko's html data flavor. Details of the CF_HTML format - // can be found at: - // http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp - // - // Essentially, we strip off all the header info and return everything else. I think - // it's safe to assume that the fragment will always contain at the beginning - // of the actual data, so look for that. - char* headerStart = strchr((char*)data, '<'); - if ( headerStart ) { - // gecko expects HTML in unicode, but CF_HTML is in UTF8. Convert it - NS_ConvertUTF8toUCS2 converter ( headerStart ); - dataLen = converter.Length() * sizeof(PRUnichar); - nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, (void*)converter.get(), dataLen, getter_AddRefs(genericDataWrapper) ); - } + else if ( strcmp(flavorStr, kNativeHTMLMime) == 0) { + // the editor folks want CF_HTML exactly as it's on the clipboard, no conversions, + // no fancy stuff. Pull it off the clipboard, stuff it into a wrapper and hand + // it back to them. + if ( FindPlatformHTML(aDataObject, anIndex, &data, &dataLen) ) + nsPrimitiveHelpers::CreatePrimitiveForData ( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) ); + else + continue; // something wrong with this flavor, keep looking for other data } - else { + else { // we probably have some form of text. The DOM only wants LF, so convert from Win32 line // endings to DOM line endings. PRInt32 signedLen = NS_STATIC_CAST(PRInt32, dataLen); @@ -639,6 +626,35 @@ nsresult nsClipboard::GetDataFromDataObject(IDataObject * aDataObject, } + +// +// FindPlatformHTML +// +// Someone asked for the OS CF_HTML flavor. We give it back to them exactly as-is. +// +PRBool +nsClipboard :: FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, PRUint32* outDataLen ) +{ + PRBool dataFound = PR_FALSE; + + if ( outData && *outData ) { + // CF_HTML is UTF8, not unicode. We also can't rely on it being null-terminated + // so we have to check the CF_HTML header for the correct length. The length we return + // is the bytecount from the beginning of the data to the end, without + // the null termination. Because it's UTF8, we're guaranteed the header is ascii (yay!). + float vers = 0.0; + PRUint32 startOfData = 0; + sscanf((char*)*outData, "Version:%f\nStartHTML:%d\nEndHTML:%d", &vers, &startOfData, outDataLen); + NS_ASSERTION(startOfData && *outDataLen, "Couldn't parse CF_HTML description header"); + + if ( *outDataLen ) + dataFound = PR_TRUE; + } + + return dataFound; +} + + // // FindURLFromLocalFile // diff --git a/widget/src/windows/nsClipboard.h b/widget/src/windows/nsClipboard.h index 1e8e9e3b4041..b8d0e587a9ea 100644 --- a/widget/src/windows/nsClipboard.h +++ b/widget/src/windows/nsClipboard.h @@ -84,6 +84,7 @@ protected: static PRBool IsInternetShortcut ( const char* inFileName ) ; static PRBool FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, PRUint32* outDataLen ) ; static PRBool FindUnicodeFromPlainText ( IDataObject* inDataObject, UINT inIndex, void** outData, PRUint32* outDataLen ) ; + static PRBool FindPlatformHTML ( IDataObject* inDataObject, UINT inIndex, void** outData, PRUint32* outDataLen ); static void ResolveShortcut ( const char* inFileName, char** outURL ) ; nsIWidget * mWindow; diff --git a/widget/src/xpwidgets/nsPrimitiveHelpers.cpp b/widget/src/xpwidgets/nsPrimitiveHelpers.cpp index 3edecf0948b4..94a32a808457 100644 --- a/widget/src/xpwidgets/nsPrimitiveHelpers.cpp +++ b/widget/src/xpwidgets/nsPrimitiveHelpers.cpp @@ -55,8 +55,8 @@ // // Given some data and the flavor it corresponds to, creates the appropriate // nsISupports* wrapper for passing across IDL boundaries. Right now, everything -// creates a two-byte |nsISupportsWString|, even "text/plain" since it is decoded -// from the native platform charset into unicode. +// creates a two-byte |nsISupportsWString|, except for "text/plain" and native +// platform HTML (CF_HTML on win32) // void nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, void* aDataBuff, @@ -65,7 +65,7 @@ nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, void* aDataB if ( !aPrimitive ) return; - if ( strcmp(aFlavor,kTextMime) == 0 ) { + if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ) { nsCOMPtr primitive; nsComponentManager::CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, nsnull, NS_GET_IID(nsISupportsString), getter_AddRefs(primitive));