2017-04-09 02:29:50 +03:00
|
|
|
/**
|
|
|
|
* WinPR: Windows Portable Runtime
|
|
|
|
* Clipboard Functions: POSIX file handling
|
|
|
|
*
|
|
|
|
* Copyright 2017 Alexei Lozovsky <a.lozovsky@gmail.com>
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
#define _FILE_OFFSET_BITS 64
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
2017-04-09 02:29:50 +03:00
|
|
|
#include <errno.h>
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
#include <dirent.h>
|
2017-04-09 02:29:50 +03:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2017-04-09 02:29:50 +03:00
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
#include <winpr/clipboard.h>
|
2017-04-09 02:29:50 +03:00
|
|
|
#include <winpr/collections.h>
|
|
|
|
#include <winpr/shell.h>
|
|
|
|
#include <winpr/string.h>
|
2017-04-09 02:29:50 +03:00
|
|
|
#include <winpr/wlog.h>
|
|
|
|
|
|
|
|
#include "clipboard.h"
|
|
|
|
#include "posix.h"
|
|
|
|
|
|
|
|
#include "../log.h"
|
|
|
|
#define TAG WINPR_TAG("clipboard.posix")
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
struct posix_file
|
|
|
|
{
|
|
|
|
char* local_name;
|
|
|
|
WCHAR* remote_name;
|
2017-04-09 02:29:50 +03:00
|
|
|
BOOL is_directory;
|
|
|
|
off_t size;
|
2017-04-09 02:29:50 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct posix_file* make_posix_file(const char* local_name, const WCHAR* remote_name)
|
|
|
|
{
|
|
|
|
struct posix_file* file = NULL;
|
2017-04-09 02:29:50 +03:00
|
|
|
struct stat statbuf;
|
2017-04-09 02:29:50 +03:00
|
|
|
|
|
|
|
file = calloc(1, sizeof(*file));
|
|
|
|
if (!file)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
file->local_name = _strdup(local_name);
|
|
|
|
file->remote_name = _wcsdup(remote_name);
|
|
|
|
|
|
|
|
if (!file->local_name || !file->remote_name)
|
|
|
|
goto error;
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
if (stat(local_name, &statbuf))
|
|
|
|
{
|
|
|
|
int err = errno;
|
|
|
|
WLog_ERR(TAG, "failed to stat %s: %s", local_name, strerror(err));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
file->is_directory = S_ISDIR(statbuf.st_mode);
|
|
|
|
file->size = statbuf.st_size;
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
return file;
|
|
|
|
|
|
|
|
error:
|
|
|
|
free(file->local_name);
|
|
|
|
free(file->remote_name);
|
|
|
|
free(file);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_posix_file(void* the_file)
|
|
|
|
{
|
|
|
|
struct posix_file* file = the_file;
|
|
|
|
|
|
|
|
if (!file)
|
|
|
|
return;
|
|
|
|
|
|
|
|
free(file->local_name);
|
|
|
|
free(file->remote_name);
|
|
|
|
free(file);
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
static unsigned char hex_to_dec(char c, BOOL* valid)
|
|
|
|
{
|
|
|
|
if (('0' <= c) && (c <= '9'))
|
|
|
|
return (c - '0');
|
|
|
|
|
|
|
|
if (('a' <= c) && (c <= 'f'))
|
|
|
|
return (c - 'a') + 10;
|
|
|
|
|
|
|
|
if (('A' <= c) && (c <= 'F'))
|
|
|
|
return (c - 'A') + 10;
|
|
|
|
|
|
|
|
*valid = FALSE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL decode_percent_encoded_byte(const char* str, const char* end, char* value)
|
|
|
|
{
|
|
|
|
BOOL valid = TRUE;
|
|
|
|
|
|
|
|
if ((end < str) || (end - str < strlen("%20")))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*value = 0;
|
|
|
|
*value |= hex_to_dec(str[1], &valid);
|
|
|
|
*value <<= 4;
|
|
|
|
*value |= hex_to_dec(str[2], &valid);
|
|
|
|
|
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
static char* decode_percent_encoded_string(const char* str, size_t len)
|
|
|
|
{
|
2017-04-09 02:29:51 +03:00
|
|
|
char* buffer = NULL;
|
|
|
|
char* next = NULL;
|
|
|
|
const char* cur = str;
|
|
|
|
const char* lim = str + len;
|
|
|
|
|
|
|
|
/* Percent decoding shrinks data length, so len bytes will be enough. */
|
|
|
|
buffer = calloc(len + 1, sizeof(char));
|
|
|
|
if (!buffer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
next = buffer;
|
|
|
|
|
|
|
|
while (cur < lim)
|
|
|
|
{
|
|
|
|
if (*cur != '%')
|
|
|
|
{
|
|
|
|
*next++ = *cur++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!decode_percent_encoded_byte(cur, lim, next))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "invalid percent encoding");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur += strlen("%20");
|
|
|
|
next += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
|
|
|
error:
|
|
|
|
free(buffer);
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
static char* concat_local_name(const char* dir, const char* file)
|
|
|
|
{
|
|
|
|
size_t len_dir = 0;
|
|
|
|
size_t len_file = 0;
|
|
|
|
char* buffer = NULL;
|
|
|
|
|
|
|
|
len_dir = strlen(dir);
|
|
|
|
len_file = strlen(file);
|
|
|
|
|
|
|
|
buffer = calloc(len_dir + 1 + len_file + 1, sizeof(char));
|
|
|
|
if (!buffer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memcpy(buffer, dir, len_dir * sizeof(char));
|
|
|
|
buffer[len_dir] = '/';
|
|
|
|
memcpy(buffer + len_dir + 1, file, len_file * sizeof(char));
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static WCHAR* concat_remote_name(const WCHAR* dir, const WCHAR* file)
|
|
|
|
{
|
|
|
|
size_t len_dir = 0;
|
|
|
|
size_t len_file = 0;
|
|
|
|
WCHAR* buffer = NULL;
|
|
|
|
|
|
|
|
len_dir = _wcslen(dir);
|
|
|
|
len_file = _wcslen(file);
|
|
|
|
|
|
|
|
buffer = calloc(len_dir + 1 + len_file + 1, sizeof(WCHAR));
|
|
|
|
if (!buffer)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
memcpy(buffer, dir, len_dir * sizeof(WCHAR));
|
|
|
|
buffer[len_dir] = L'\\';
|
|
|
|
memcpy(buffer + len_dir + 1, file, len_file * sizeof(WCHAR));
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL add_file_to_list(const char* local_name, const WCHAR* remote_name, wArrayList* files);
|
|
|
|
|
|
|
|
static BOOL add_directory_entry_to_list(const char* local_dir_name, const WCHAR* remote_dir_name,
|
|
|
|
const struct dirent* entry, wArrayList* files)
|
|
|
|
{
|
|
|
|
BOOL result = FALSE;
|
|
|
|
char* local_name = NULL;
|
|
|
|
WCHAR* remote_name = NULL;
|
|
|
|
WCHAR* remote_base_name = NULL;
|
|
|
|
|
|
|
|
/* Skip special directory entries. */
|
|
|
|
if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* As noted in add_file_to_list(), it is not always correct to assume
|
|
|
|
* that that file names are encoded in UTF-8. However, this is the
|
|
|
|
* most sane thing to do at the moment.
|
|
|
|
*/
|
|
|
|
if (!ConvertToUnicode(CP_UTF8, 0, entry->d_name, -1, &remote_base_name, 0))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Unicode conversion failed for %s", entry->d_name);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
local_name = concat_local_name(local_dir_name, entry->d_name);
|
|
|
|
remote_name = concat_remote_name(remote_dir_name, remote_base_name);
|
|
|
|
|
|
|
|
if (local_name && remote_name)
|
|
|
|
result = add_file_to_list(local_name, remote_name, files);
|
|
|
|
|
|
|
|
free(remote_base_name);
|
|
|
|
free(remote_name);
|
|
|
|
free(local_name);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL do_add_directory_contents_to_list(const char* local_name, const WCHAR* remote_name,
|
|
|
|
DIR* dirp, wArrayList* files)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For some reason POSIX does not require readdir() to be thread-safe.
|
|
|
|
* However, readdir_r() has really insane interface and is pretty bad
|
|
|
|
* replacement for it. Fortunately, most C libraries guarantee thread-
|
|
|
|
* safety of readdir() when it is used for distinct directory streams.
|
|
|
|
*
|
|
|
|
* Thus we can use readdir() in multithreaded applications if we are
|
|
|
|
* sure that it will not corrupt some global data. It would be nice
|
|
|
|
* to have a compile-time check for this here, but some C libraries
|
|
|
|
* do not provide a #define because of reasons (I'm looking at you,
|
|
|
|
* musl). We should not be breaking people's builds because of that,
|
|
|
|
* so we do nothing and proceed with fingers crossed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
struct dirent* entry = NULL;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
entry = readdir(dirp);
|
|
|
|
if (!entry)
|
|
|
|
{
|
|
|
|
int err = errno;
|
|
|
|
if (!err)
|
|
|
|
break;
|
|
|
|
|
|
|
|
WLog_ERR(TAG, "failed to read directory: %s", strerror(err));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!add_directory_entry_to_list(local_name, remote_name, entry, files))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL add_directory_contents_to_list(const char* local_name, const WCHAR* remote_name,
|
|
|
|
wArrayList* files)
|
|
|
|
{
|
|
|
|
BOOL result = FALSE;
|
|
|
|
DIR* dirp = NULL;
|
|
|
|
|
|
|
|
#ifdef WITH_DEBUG_WCLIPBOARD
|
|
|
|
WLog_DBG(TAG, "adding directory: %s", local_name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
dirp = opendir(local_name);
|
|
|
|
if (!dirp)
|
|
|
|
{
|
|
|
|
int err = errno;
|
|
|
|
WLog_ERR(TAG, "failed to open directory %s: %s", local_name, strerror(err));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = do_add_directory_contents_to_list(local_name, remote_name, dirp, files);
|
|
|
|
|
|
|
|
if (closedir(dirp))
|
|
|
|
{
|
|
|
|
int err = errno;
|
|
|
|
WLog_WARN(TAG, "failed to close directory: %s", strerror(err));
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
static BOOL add_file_to_list(const char* local_name, const WCHAR* remote_name, wArrayList* files)
|
|
|
|
{
|
|
|
|
struct posix_file* file = NULL;
|
|
|
|
|
|
|
|
#ifdef WITH_DEBUG_WCLIPBOARD
|
|
|
|
WLog_DBG(TAG, "adding file: %s", local_name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
file = make_posix_file(local_name, remote_name);
|
|
|
|
if (!file)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (ArrayList_Add(files, file) < 0)
|
|
|
|
{
|
|
|
|
free_posix_file(file);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
if (file->is_directory)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is effectively a recursive call, but we do not track
|
|
|
|
* recursion depth, thus filesystem loops can cause a crash.
|
|
|
|
*/
|
|
|
|
if (!add_directory_contents_to_list(local_name, remote_name, files))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char* basename(const char* name)
|
|
|
|
{
|
|
|
|
const char* c = name;
|
|
|
|
const char* last_name = name;
|
|
|
|
|
|
|
|
while (*c++)
|
|
|
|
{
|
|
|
|
if (*c == '/')
|
|
|
|
last_name = c + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return last_name;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:51 +03:00
|
|
|
static BOOL process_file_name(const char* local_name, wArrayList* files)
|
|
|
|
{
|
2017-04-09 02:29:51 +03:00
|
|
|
BOOL result = FALSE;
|
|
|
|
const char* base_name = NULL;
|
|
|
|
WCHAR* remote_name = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start with the base name of the file. text/uri-list contains the
|
|
|
|
* exact files selected by the user, and we want the remote files
|
|
|
|
* to have names relative to that selection.
|
|
|
|
*
|
|
|
|
* Note that local file names are not actually guaranteed to be
|
|
|
|
* encoded in UTF-8. Filesystems and users can use whatever they
|
|
|
|
* want. The OS does not care, aside from special treatment of
|
|
|
|
* '\0' and '/' bytes. But we need to make some decision here.
|
|
|
|
* Assuming UTF-8 is currently the most sane thing.
|
|
|
|
*/
|
|
|
|
base_name = basename(local_name);
|
|
|
|
if (!ConvertToUnicode(CP_UTF8, 0, base_name, -1, &remote_name, 0))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "Unicode conversion failed for %s", base_name);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = add_file_to_list(local_name, remote_name, files);
|
|
|
|
out:
|
|
|
|
free(remote_name);
|
|
|
|
|
|
|
|
return result;
|
2017-04-09 02:29:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL process_uri(const char* uri, size_t uri_len, wArrayList* files)
|
|
|
|
{
|
|
|
|
BOOL result = FALSE;
|
|
|
|
char* name = NULL;
|
|
|
|
|
|
|
|
#ifdef WITH_DEBUG_WCLIPBOARD
|
|
|
|
WLog_DBG(TAG, "processing URI: %.*s", uri_len, uri);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ((uri_len < strlen("file://")) || strncmp(uri, "file://", strlen("file://")))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "non-'file://' URI schemes are not supported");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = decode_percent_encoded_string(uri + strlen("file://"), uri_len - strlen("file://"));
|
|
|
|
if (!name)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
result = process_file_name(name, files);
|
|
|
|
out:
|
|
|
|
free(name);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
static BOOL process_uri_list(const char* data, size_t length, wArrayList* files)
|
|
|
|
{
|
2017-04-09 02:29:51 +03:00
|
|
|
const char* cur = data;
|
|
|
|
const char* lim = data + length;
|
|
|
|
const char* start = NULL;
|
|
|
|
const char* stop = NULL;
|
|
|
|
|
|
|
|
#ifdef WITH_DEBUG_WCLIPBOARD
|
|
|
|
WLog_DBG(TAG, "processing URI list:\n%.*s", length, data);
|
|
|
|
#endif
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
ArrayList_Clear(files);
|
2017-04-09 02:29:51 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The "text/uri-list" Internet Media Type is specified by RFC 2483.
|
|
|
|
*
|
|
|
|
* While the RFCs 2046 and 2483 require the lines of text/... formats
|
|
|
|
* to be terminated by CRLF sequence, be prepared for those who don't
|
|
|
|
* read the spec, use plain LFs, and don't leave the trailing CRLF.
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (cur < lim)
|
|
|
|
{
|
|
|
|
BOOL comment = (*cur == '#');
|
|
|
|
|
|
|
|
start = cur;
|
|
|
|
stop = cur;
|
|
|
|
|
|
|
|
for (stop = cur; stop < lim; stop++)
|
|
|
|
{
|
|
|
|
if (*stop == '\r')
|
|
|
|
{
|
|
|
|
if ((stop + 1 < lim) && (*(stop + 1) == '\n'))
|
|
|
|
cur = stop + 2;
|
|
|
|
else
|
|
|
|
cur = stop + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*stop == '\n')
|
|
|
|
{
|
|
|
|
cur = stop + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (stop == lim)
|
|
|
|
cur = lim;
|
|
|
|
|
|
|
|
if (comment)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!process_uri(start, stop - start, files))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
static BOOL convert_local_file_to_filedescriptor(const struct posix_file* file,
|
|
|
|
FILEDESCRIPTOR* descriptor)
|
|
|
|
{
|
|
|
|
size_t remote_len = 0;
|
|
|
|
|
|
|
|
descriptor->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_SHOWPROGRESSUI;
|
|
|
|
|
|
|
|
if (file->is_directory)
|
|
|
|
{
|
|
|
|
descriptor->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
descriptor->nFileSizeLow = 0;
|
|
|
|
descriptor->nFileSizeHigh = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
descriptor->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
|
|
descriptor->nFileSizeLow = (file->size >> 0) & 0xFFFFFFFF;
|
|
|
|
descriptor->nFileSizeHigh = (file->size >> 32) & 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
remote_len = _wcslen(file->remote_name);
|
|
|
|
if (remote_len + 1 > ARRAYSIZE(descriptor->fileName))
|
|
|
|
{
|
|
|
|
WLog_ERR(TAG, "file name too long (%"PRIuz" characters)", remote_len);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(descriptor->fileName, file->remote_name, remote_len * sizeof(WCHAR));
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
static FILEDESCRIPTOR* convert_local_file_list_to_filedescriptors(wArrayList* files)
|
|
|
|
{
|
2017-04-09 02:29:50 +03:00
|
|
|
int i;
|
|
|
|
int count = 0;
|
|
|
|
FILEDESCRIPTOR* descriptors = NULL;
|
|
|
|
|
|
|
|
count = ArrayList_Count(files);
|
|
|
|
|
|
|
|
descriptors = calloc(count, sizeof(descriptors[0]));
|
|
|
|
if (!descriptors)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
const struct posix_file* file = ArrayList_GetItem(files, i);
|
|
|
|
|
|
|
|
if (!convert_local_file_to_filedescriptor(file, &descriptors[i]))
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return descriptors;
|
|
|
|
|
|
|
|
error:
|
|
|
|
free(descriptors);
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* convert_uri_list_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
|
|
|
|
const void* data, UINT32* pSize)
|
|
|
|
{
|
|
|
|
FILEDESCRIPTOR* descriptors = NULL;
|
|
|
|
|
|
|
|
if (!clipboard || !data || !pSize)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (formatId != ClipboardGetFormatId(clipboard, "text/uri-list"))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!process_uri_list((const char*) data, *pSize, clipboard->localFiles))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
descriptors = convert_local_file_list_to_filedescriptors(clipboard->localFiles);
|
|
|
|
if (!descriptors)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*pSize = ArrayList_Count(clipboard->localFiles) * sizeof(FILEDESCRIPTOR);
|
|
|
|
|
|
|
|
return descriptors;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard)
|
|
|
|
{
|
|
|
|
UINT32 file_group_format_id;
|
|
|
|
UINT32 local_file_format_id;
|
|
|
|
|
|
|
|
file_group_format_id = ClipboardRegisterFormat(clipboard, "FileGroupDescriptorW");
|
|
|
|
local_file_format_id = ClipboardRegisterFormat(clipboard, "text/uri-list");
|
|
|
|
if (!file_group_format_id || !local_file_format_id)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
clipboard->localFiles = ArrayList_New(FALSE);
|
|
|
|
if (!clipboard->localFiles)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ArrayList_Object(clipboard->localFiles)->fnObjectFree = free_posix_file;
|
|
|
|
|
|
|
|
if (!ClipboardRegisterSynthesizer(clipboard,
|
|
|
|
local_file_format_id, file_group_format_id,
|
|
|
|
convert_uri_list_to_filedescriptors))
|
|
|
|
goto error_free_local_files;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
error_free_local_files:
|
|
|
|
ArrayList_Free(clipboard->localFiles);
|
|
|
|
clipboard->localFiles = NULL;
|
|
|
|
error:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
BOOL ClipboardInitPosixFileSubsystem(wClipboard* clipboard)
|
|
|
|
{
|
|
|
|
if (!clipboard)
|
|
|
|
return FALSE;
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
if (!register_file_formats_and_synthesizers(clipboard))
|
|
|
|
return FALSE;
|
|
|
|
|
2017-04-09 02:29:50 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|