winemac: Add support for CF_HDROP clipboard format, mapped to/from Cocoa's NSFilenamesPboardType.

This commit is contained in:
Ken Thomases 2013-03-13 16:52:50 -05:00 committed by Alexandre Julliard
parent 95d5270a0d
commit bff19b1739
1 changed files with 218 additions and 0 deletions

View File

@ -26,6 +26,8 @@
#include "macdrv.h"
#include "winuser.h"
#include "shellapi.h"
#include "shlobj.h"
#include "wine/list.h"
#include "wine/server.h"
#include "wine/unicode.h"
@ -70,6 +72,7 @@ typedef struct
static HANDLE import_clipboard_data(CFDataRef data);
static HANDLE import_bmp_to_bitmap(CFDataRef data);
static HANDLE import_bmp_to_dib(CFDataRef data);
static HANDLE import_nsfilenames_to_hdrop(CFDataRef data);
static HANDLE import_oemtext_to_text(CFDataRef data);
static HANDLE import_oemtext_to_unicodetext(CFDataRef data);
static HANDLE import_text_to_oemtext(CFDataRef data);
@ -83,6 +86,7 @@ static HANDLE import_utf8_to_unicodetext(CFDataRef data);
static CFDataRef export_clipboard_data(HANDLE data);
static CFDataRef export_bitmap_to_bmp(HANDLE data);
static CFDataRef export_dib_to_bmp(HANDLE data);
static CFDataRef export_hdrop_to_filenames(HANDLE data);
static CFDataRef export_oemtext_to_utf8(HANDLE data);
static CFDataRef export_text_to_utf8(HANDLE data);
static CFDataRef export_unicodetext_to_utf8(HANDLE data);
@ -181,6 +185,9 @@ static const struct
{ CF_BITMAP, CFSTR("org.winehq.builtin.bitmap"), import_bmp_to_bitmap, export_bitmap_to_bmp, FALSE },
{ CF_BITMAP, CFSTR("com.microsoft.bmp"), import_bmp_to_bitmap, export_bitmap_to_bmp, TRUE },
{ CF_HDROP, CFSTR("org.winehq.builtin.hdrop"), import_clipboard_data, export_clipboard_data, FALSE },
{ CF_HDROP, CFSTR("NSFilenamesPboardType"), import_nsfilenames_to_hdrop, export_hdrop_to_filenames, TRUE },
};
static const WCHAR wszRichTextFormat[] = {'R','i','c','h',' ','T','e','x','t',' ','F','o','r','m','a','t',0};
@ -670,6 +677,124 @@ static HANDLE import_bmp_to_dib(CFDataRef data)
}
/**************************************************************************
* import_nsfilenames_to_hdrop
*
* Import NSFilenamesPboardType data, converting the property-list-
* serialized array of path strings to CF_HDROP.
*/
static HANDLE import_nsfilenames_to_hdrop(CFDataRef data)
{
HDROP hdrop = NULL;
CFArrayRef names;
CFIndex count, i;
size_t len;
char *buffer = NULL;
WCHAR **paths = NULL;
DROPFILES* dropfiles;
UniChar* p;
TRACE("data %s\n", debugstr_cf(data));
names = (CFArrayRef)CFPropertyListCreateWithData(NULL, data, kCFPropertyListImmutable,
NULL, NULL);
if (!names || CFGetTypeID(names) != CFArrayGetTypeID())
{
WARN("failed to interpret data as a CFArray\n");
goto done;
}
count = CFArrayGetCount(names);
len = 0;
for (i = 0; i < count; i++)
{
CFIndex this_len;
CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
TRACE(" %s\n", debugstr_cf(name));
if (CFGetTypeID(name) != CFStringGetTypeID())
{
WARN("non-string in array\n");
goto done;
}
this_len = CFStringGetMaximumSizeOfFileSystemRepresentation(name);
if (this_len > len)
len = this_len;
}
buffer = HeapAlloc(GetProcessHeap(), 0, len);
if (!buffer)
{
WARN("failed to allocate buffer for file-system representations\n");
goto done;
}
paths = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(paths[0]));
if (!paths)
{
WARN("failed to allocate array of DOS paths\n");
goto done;
}
for (i = 0; i < count; i++)
{
CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(names, i);
if (!CFStringGetFileSystemRepresentation(name, buffer, len))
{
WARN("failed to get file-system representation for %s\n", debugstr_cf(name));
goto done;
}
paths[i] = wine_get_dos_file_name(buffer);
if (!paths[i])
{
WARN("failed to get DOS path for %s\n", debugstr_a(buffer));
goto done;
}
}
len = 1; /* for the terminating null */
for (i = 0; i < count; i++)
len += strlenW(paths[i]) + 1;
hdrop = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(*dropfiles) + len * sizeof(WCHAR));
if (!hdrop || !(dropfiles = GlobalLock(hdrop)))
{
WARN("failed to allocate HDROP\n");
GlobalFree(hdrop);
hdrop = NULL;
goto done;
}
dropfiles->pFiles = sizeof(*dropfiles);
dropfiles->pt.x = 0;
dropfiles->pt.y = 0;
dropfiles->fNC = FALSE;
dropfiles->fWide = TRUE;
p = (WCHAR*)(dropfiles + 1);
for (i = 0; i < count; i++)
{
strcpyW(p, paths[i]);
p += strlenW(p) + 1;
}
*p = 0;
GlobalUnlock(hdrop);
done:
if (paths)
{
for (i = 0; i < count; i++)
HeapFree(GetProcessHeap(), 0, paths[i]);
HeapFree(GetProcessHeap(), 0, paths);
}
HeapFree(GetProcessHeap(), 0, buffer);
if (names) CFRelease(names);
return hdrop;
}
/**************************************************************************
* import_oemtext_to_text
*
@ -923,6 +1048,99 @@ static CFDataRef export_dib_to_bmp(HANDLE data)
}
/**************************************************************************
* export_hdrop_to_filenames
*
* Export CF_HDROP to NSFilenamesPboardType data, which is a CFArray of
* CFStrings (holding Unix paths) which is serialized as a property list.
*/
static CFDataRef export_hdrop_to_filenames(HANDLE data)
{
CFDataRef ret = NULL;
DROPFILES *dropfiles;
CFMutableArrayRef filenames = NULL;
void *p;
WCHAR *buffer = NULL;
size_t buffer_len = 0;
TRACE("data %p\n", data);
if (!(dropfiles = GlobalLock(data)))
{
WARN("failed to lock data %p\n", data);
goto done;
}
filenames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (!filenames)
{
WARN("failed to create filenames array\n");
goto done;
}
p = (char*)dropfiles + dropfiles->pFiles;
while (dropfiles->fWide ? *(WCHAR*)p : *(char*)p)
{
char *unixname;
CFStringRef filename;
TRACE(" %s\n", dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
if (dropfiles->fWide)
unixname = wine_get_unix_file_name(p);
else
{
int len = MultiByteToWideChar(CP_ACP, 0, p, -1, NULL, 0);
if (len)
{
if (len > buffer_len)
{
HeapFree(GetProcessHeap(), 0, buffer);
buffer_len = len * 2;
buffer = HeapAlloc(GetProcessHeap(), 0, buffer_len * sizeof(*buffer));
}
MultiByteToWideChar(CP_ACP, 0, p, -1, buffer, buffer_len);
unixname = wine_get_unix_file_name(buffer);
}
else
unixname = NULL;
}
if (!unixname)
{
WARN("failed to convert DOS path to Unix: %s\n",
dropfiles->fWide ? debugstr_w(p) : debugstr_a(p));
goto done;
}
if (dropfiles->fWide)
p = (WCHAR*)p + strlenW(p) + 1;
else
p = (char*)p + strlen(p) + 1;
filename = CFStringCreateWithFileSystemRepresentation(NULL, unixname);
HeapFree(GetProcessHeap(), 0, unixname);
if (!filename)
{
WARN("failed to create CFString from Unix path %s\n", debugstr_a(unixname));
goto done;
}
CFArrayAppendValue(filenames, filename);
CFRelease(filename);
}
ret = CFPropertyListCreateData(NULL, filenames, kCFPropertyListXMLFormat_v1_0, 0, NULL);
done:
HeapFree(GetProcessHeap(), 0, buffer);
GlobalUnlock(data);
if (filenames) CFRelease(filenames);
TRACE(" -> %s\n", debugstr_cf(ret));
return ret;
}
/**************************************************************************
* export_oemtext_to_utf8
*