20#include <winpr/config.h>
21#include <winpr/platform.h>
24WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
25WINPR_PRAGMA_DIAG_IGNORED_UNUSED_MACRO
27#define _FILE_OFFSET_BITS 64
33#include <winpr/wtypes.h>
36#include <winpr/clipboard.h>
37#include <winpr/collections.h>
38#include <winpr/file.h>
39#include <winpr/shell.h>
40#include <winpr/string.h>
41#include <winpr/wlog.h>
42#include <winpr/path.h>
43#include <winpr/print.h>
46#include "synthetic_file.h"
49#define TAG WINPR_TAG("clipboard.synthetic.file")
51static const char* mime_uri_list =
"text/uri-list";
52static const char* mime_FileGroupDescriptorW =
"FileGroupDescriptorW";
53static const char* mime_gnome_copied_files =
"x-special/gnome-copied-files";
54static const char* mime_mate_copied_files =
"x-special/mate-copied-files";
64 DWORD dwFileAttributes;
72void free_synthetic_file(
struct synthetic_file* file);
74static struct synthetic_file* make_synthetic_file(
const WCHAR* local_name,
const WCHAR* remote_name)
76 struct synthetic_file* file =
nullptr;
78 HANDLE hFind =
nullptr;
80 WINPR_ASSERT(local_name);
81 WINPR_ASSERT(remote_name);
83 hFind = FindFirstFileW(local_name, &fd);
84 if (INVALID_HANDLE_VALUE == hFind)
86 WLog_ERR(TAG,
"FindFirstFile failed (%" PRIu32
")", GetLastError());
91 file = calloc(1,
sizeof(*file));
95 file->fd = INVALID_HANDLE_VALUE;
97 file->local_name = _wcsdup(local_name);
98 if (!file->local_name)
101 file->remote_name = _wcsdup(remote_name);
102 if (!file->remote_name)
106 const size_t len = _wcslen(file->remote_name);
107 if (S_OK != PathCchConvertStyleW(file->remote_name, len, PATH_STYLE_WINDOWS))
111 file->dwFileAttributes = fd.dwFileAttributes;
112 file->ftCreationTime = fd.ftCreationTime;
113 file->ftLastWriteTime = fd.ftLastWriteTime;
114 file->ftLastAccessTime = fd.ftLastAccessTime;
115 file->nFileSizeHigh = fd.nFileSizeHigh;
116 file->nFileSizeLow = fd.nFileSizeLow;
120 free_synthetic_file(file);
124static UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force);
126void free_synthetic_file(
struct synthetic_file* file)
131 synthetic_file_read_close(file, TRUE);
133 free(file->local_name);
134 free(file->remote_name);
142static WCHAR* convert_local_name_component_to_remote(wClipboard* clipboard,
const WCHAR* local_name)
144 wClipboardDelegate* delegate = ClipboardGetDelegate(clipboard);
145 WCHAR* remote_name =
nullptr;
147 WINPR_ASSERT(delegate);
149 remote_name = _wcsdup(local_name);
160 if (!delegate->IsFileNameComponentValid(remote_name))
162 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
163 ConvertWCharToUtf8(local_name, name,
sizeof(name) - 1);
164 WLog_ERR(TAG,
"invalid file name component: %s", name);
174static WCHAR* concat_file_name(
const WCHAR* dir,
const WCHAR* file)
178 const WCHAR slash =
'/';
179 WCHAR* buffer =
nullptr;
184 len_dir = _wcslen(dir);
185 len_file = _wcslen(file);
186 buffer = calloc(len_dir + 1 + len_file + 2,
sizeof(WCHAR));
191 memcpy(buffer, dir, len_dir *
sizeof(WCHAR));
192 buffer[len_dir] = slash;
193 memcpy(buffer + len_dir + 1, file, len_file *
sizeof(WCHAR));
197static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
198 const WCHAR* remote_name, wArrayList* files);
200static BOOL add_directory_entry_to_list(wClipboard* clipboard,
const WCHAR* local_dir_name,
201 const WCHAR* remote_dir_name,
205 WCHAR* local_name =
nullptr;
206 WCHAR* remote_name =
nullptr;
207 WCHAR* remote_base_name =
nullptr;
209 WCHAR dotbuffer[6] = WINPR_C_ARRAY_INIT;
210 WCHAR dotdotbuffer[6] = WINPR_C_ARRAY_INIT;
211 const WCHAR* dot = InitializeConstWCharFromUtf8(
".", dotbuffer, ARRAYSIZE(dotbuffer));
212 const WCHAR* dotdot = InitializeConstWCharFromUtf8(
"..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
214 WINPR_ASSERT(clipboard);
215 WINPR_ASSERT(local_dir_name);
216 WINPR_ASSERT(remote_dir_name);
217 WINPR_ASSERT(pFileData);
222 if ((_wcscmp(pFileData->cFileName, dot) == 0) || (_wcscmp(pFileData->cFileName, dotdot) == 0))
225 remote_base_name = convert_local_name_component_to_remote(clipboard, pFileData->cFileName);
227 if (!remote_base_name)
230 local_name = concat_file_name(local_dir_name, pFileData->cFileName);
231 remote_name = concat_file_name(remote_dir_name, remote_base_name);
233 if (local_name && remote_name)
234 result = add_file_to_list(clipboard, local_name, remote_name, files);
236 free(remote_base_name);
242static BOOL do_add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
243 const WCHAR* remote_name, WCHAR* namebuf,
246 WINPR_ASSERT(clipboard);
247 WINPR_ASSERT(local_name);
248 WINPR_ASSERT(remote_name);
250 WINPR_ASSERT(namebuf);
253 HANDLE hFind = FindFirstFileW(namebuf, &FindData);
254 if (INVALID_HANDLE_VALUE == hFind)
256 WLog_ERR(TAG,
"FindFirstFile failed (%" PRIu32
")", GetLastError());
261 if (!add_directory_entry_to_list(clipboard, local_name, remote_name, &FindData, files))
267 BOOL bRet = FindNextFileW(hFind, &FindData);
271 if (ERROR_NO_MORE_FILES == GetLastError())
273 WLog_WARN(TAG,
"FindNextFile failed (%" PRIu32
")", GetLastError());
281static BOOL add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
282 const WCHAR* remote_name, wArrayList* files)
290 const char buffer[6] = {
'/',
'\0',
'*',
'\0',
'\0',
'\0' };
292 const size_t wildcardLen = ARRAYSIZE(buffer) /
sizeof(WCHAR);
294 WINPR_ASSERT(clipboard);
295 WINPR_ASSERT(local_name);
296 WINPR_ASSERT(remote_name);
299 size_t len = _wcslen(local_name);
300 WCHAR* namebuf = calloc(len + wildcardLen,
sizeof(WCHAR));
304 _wcsncat(namebuf, local_name, len);
305 _wcsncat(namebuf, wildcard.w, wildcardLen);
307 result = do_add_directory_contents_to_list(clipboard, local_name, remote_name, namebuf, files);
313static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
314 const WCHAR* remote_name, wArrayList* files)
316 struct synthetic_file* file =
nullptr;
318 WINPR_ASSERT(clipboard);
319 WINPR_ASSERT(local_name);
320 WINPR_ASSERT(remote_name);
323 file = make_synthetic_file(local_name, remote_name);
328 if (!ArrayList_Append(files, file))
330 free_synthetic_file(file);
334 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
340 if (!add_directory_contents_to_list(clipboard, local_name, remote_name, files))
347static const WCHAR* get_basename(
const WCHAR* name)
349 const WCHAR* c = name;
350 const WCHAR* last_name = name;
351 const WCHAR slash =
'/';
364static BOOL process_file_name(wClipboard* clipboard,
const WCHAR* local_name, wArrayList* files)
367 const WCHAR* base_name =
nullptr;
368 WCHAR* remote_name =
nullptr;
370 WINPR_ASSERT(clipboard);
371 WINPR_ASSERT(local_name);
379 base_name = get_basename(local_name);
380 remote_name = convert_local_name_component_to_remote(clipboard, base_name);
385 result = add_file_to_list(clipboard, local_name, remote_name, files);
390static BOOL process_uri(wClipboard* clipboard,
const char* uri,
size_t uri_len)
394 char* name =
nullptr;
396 WINPR_ASSERT(clipboard);
398 name = parse_uri_to_local_file(uri, uri_len);
401 WCHAR* wname =
nullptr;
409 wname = ConvertUtf8ToWCharAlloc(name,
nullptr);
411 result = process_file_name(clipboard, wname, clipboard->localFiles);
420static BOOL process_uri_list(wClipboard* clipboard,
const char* data,
size_t length)
422 const char* cur = data;
423 const char* lim = data + length;
425 WINPR_ASSERT(clipboard);
428 WLog_VRB(TAG,
"processing URI list:\n%.*s", WINPR_ASSERTING_INT_CAST(
int, length), data);
429 ArrayList_Clear(clipboard->localFiles);
441 BOOL comment = (*cur ==
'#');
442 const char* start = cur;
443 const char* stop = cur;
445 for (; stop < lim; stop++)
449 if ((stop + 1 < lim) && (*(stop + 1) ==
'\n'))
466 if (strnlen(start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)) < 1)
474 if (!process_uri(clipboard, start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)))
481static BOOL convert_local_file_to_filedescriptor(
const struct synthetic_file* file,
484 size_t remote_len = 0;
487 WINPR_ASSERT(descriptor);
489 descriptor->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI;
491 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
493 descriptor->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
494 descriptor->nFileSizeLow = 0;
495 descriptor->nFileSizeHigh = 0;
499 descriptor->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
500 descriptor->nFileSizeLow = file->nFileSizeLow;
501 descriptor->nFileSizeHigh = file->nFileSizeHigh;
504 descriptor->ftLastWriteTime = file->ftLastWriteTime;
506 remote_len = _wcsnlen(file->remote_name, ARRAYSIZE(descriptor->cFileName));
508 if (remote_len >= ARRAYSIZE(descriptor->cFileName))
510 WLog_ERR(TAG,
"file name too long (%" PRIuz
" characters)", remote_len);
514 memcpy(descriptor->cFileName, file->remote_name, remote_len *
sizeof(WCHAR));
518static FILEDESCRIPTORW* convert_local_file_list_to_filedescriptors(wArrayList* files)
523 count = ArrayList_Count(files);
530 for (
size_t i = 0; i < count; i++)
532 const struct synthetic_file* file = ArrayList_GetItem(files, i);
534 if (!convert_local_file_to_filedescriptor(file, &descriptors[i]))
544static void* convert_any_uri_list_to_filedescriptors(wClipboard* clipboard,
545 WINPR_ATTR_UNUSED UINT32 formatId,
550 WINPR_ASSERT(clipboard);
553 descriptors = convert_local_file_list_to_filedescriptors(clipboard->localFiles);
558 *pSize = (UINT32)ArrayList_Count(clipboard->localFiles) *
sizeof(
FILEDESCRIPTORW);
559 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
563static void* convert_uri_list_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
564 const void* data, UINT32* pSize)
566 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
569 "Unuspported destination format %s [0x%04" PRIx32
570 "], trying to convert from %s [0x%04" PRIx32
"]",
571 ClipboardGetFormatName(clipboard, formatId), formatId,
572 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
575 if (clipboard->formatId != ClipboardGetFormatId(clipboard, mime_uri_list))
578 "Unuspported destination format %s [0x%04" PRIx32
579 "], trying to convert from %s [0x%04" PRIx32
"]",
580 ClipboardGetFormatName(clipboard, formatId), formatId,
581 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
584 if (!process_uri_list(clipboard, (
const char*)data, *pSize))
586 return convert_any_uri_list_to_filedescriptors(clipboard, clipboard->formatId, pSize);
589static BOOL process_files(wClipboard* clipboard,
const char* data, UINT32 pSize,
const char* prefix)
591 WINPR_ASSERT(prefix);
593 const size_t prefix_len = strlen(prefix);
595 WINPR_ASSERT(clipboard);
597 ArrayList_Clear(clipboard->localFiles);
599 if (!data || (pSize < prefix_len))
601 if (strncmp(data, prefix, prefix_len) != 0)
604 if (pSize < prefix_len)
606 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, prefix_len);
609 char* copy = strndup(data, pSize);
614 char* endptr =
nullptr;
615 char* tok = strtok_s(copy,
"\n", &endptr);
618 const size_t tok_len = strnlen(tok, pSize);
619 if (!process_uri(clipboard, tok, tok_len))
623 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, tok_len);
624 tok = strtok_s(
nullptr,
"\n", &endptr);
635static BOOL process_gnome_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
637 return process_files(clipboard, data, pSize,
"copy\n");
640static BOOL process_mate_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
642 return process_files(clipboard, data, pSize,
"copy\n");
645static void* convert_gnome_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
646 const void* data, UINT32* pSize)
648 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
651 "Unuspported destination format %s [0x%04" PRIx32
652 "], trying to convert from %s [0x%04" PRIx32
"]",
653 ClipboardGetFormatName(clipboard, formatId), formatId,
654 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
657 if (clipboard->formatId != ClipboardGetFormatId(clipboard, mime_gnome_copied_files))
660 "Unuspported destination format %s [0x%04" PRIx32
661 "], trying to convert from %s [0x%04" PRIx32
"]",
662 ClipboardGetFormatName(clipboard, formatId), formatId,
663 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
666 if (!process_gnome_copied_files(clipboard, (
const char*)data, *pSize))
668 return convert_any_uri_list_to_filedescriptors(clipboard, clipboard->formatId, pSize);
671static void* convert_mate_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
672 const void* data, UINT32* pSize)
674 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
677 "Unuspported destination format %s [0x%04" PRIx32
678 "], trying to convert from %s [0x%04" PRIx32
"]",
679 ClipboardGetFormatName(clipboard, formatId), formatId,
680 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
683 if (clipboard->formatId != ClipboardGetFormatId(clipboard, mime_mate_copied_files))
686 "Unuspported destination format %s [0x%04" PRIx32
687 "], trying to convert from %s [0x%04" PRIx32
"]",
688 ClipboardGetFormatName(clipboard, formatId), formatId,
689 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
693 if (!process_mate_copied_files(clipboard, (
const char*)data, *pSize))
696 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
700static size_t count_special_chars(
const WCHAR* str,
size_t charLen)
703 const WCHAR* start = str;
704 const WCHAR* end = &str[charLen];
707 while ((start < end) && (*start))
709 const WCHAR sharp =
'#';
710 const WCHAR questionmark =
'?';
711 const WCHAR star =
'*';
712 const WCHAR exclamationmark =
'!';
713 const WCHAR percent =
'%';
715 if ((*start == sharp) || (*start == questionmark) || (*start == star) ||
716 (*start == exclamationmark) || (*start == percent))
725static const char* stop_at_special_chars(
const char* str)
727 const char* start = str;
732 if (*start ==
'#' || *start ==
'?' || *start ==
'*' || *start ==
'!' || *start ==
'%')
742WINPR_ATTR_MALLOC(free, 1)
743static
void* convert_filedescriptors_to_file_list(wClipboard* clipboard, UINT32 formatId,
744 const
void* data, UINT32* pSize,
745 const
char* header, const
char* lineprefix,
746 const
char* lineending, BOOL skip_last_lineending)
753 backslash.c[0] =
'\\';
754 backslash.c[1] =
'\0';
756 UINT32 nrDescriptors = 0;
757 size_t baseLength = 0;
758 size_t header_len = strlen(header);
759 size_t lineprefix_len = strlen(lineprefix);
760 size_t lineending_len = strlen(lineending);
762 if (!clipboard || !data || !pSize)
765 if (*pSize <
sizeof(UINT32))
768 if (clipboard->delegate.basePath)
769 baseLength = strnlen(clipboard->delegate.basePath, MAX_PATH);
774 wStream sbuffer = WINPR_C_ARRAY_INIT;
775 wStream* s = Stream_StaticConstInit(&sbuffer, data, *pSize);
776 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
779 Stream_Read_UINT32(s, nrDescriptors);
783 if ((count < 1) || (count != nrDescriptors))
788 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
792 const size_t decoration_len = lineprefix_len + lineending_len + baseLength + 1;
793 size_t alloc = header_len;
796 for (
size_t x = 0; x < count; x++)
800 if (winpr_wcsnchr(dsc->cFileName, ARRAYSIZE(dsc->cFileName), backslash.w) ==
nullptr)
802 alloc += ARRAYSIZE(dsc->cFileName) *
805 alloc += count_special_chars(dsc->cFileName, ARRAYSIZE(dsc->cFileName)) *
sizeof(WCHAR);
806 alloc += decoration_len;
813 char* dst = calloc(alloc,
sizeof(
char));
818 (void)_snprintf(&dst[0], alloc,
"%s", header);
820 size_t pos = header_len;
822 for (
size_t x = 0; x < count; x++)
826 if (winpr_wcsnchr(dsc->cFileName, ARRAYSIZE(dsc->cFileName), backslash.w) !=
nullptr)
831 char curName[520] = WINPR_C_ARRAY_INIT;
832 const char* stop_at =
nullptr;
833 const char* previous_at =
nullptr;
835 if (ConvertWCharNToUtf8(dsc->cFileName, ARRAYSIZE(dsc->cFileName), curName,
836 ARRAYSIZE(curName)) < 0)
839 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s/", lineprefix, clipboard->delegate.basePath);
846 previous_at = curName;
847 while ((stop_at = stop_at_special_chars(previous_at)) !=
nullptr)
849 const intptr_t diff = stop_at - previous_at;
852 char* tmp = strndup(previous_at, WINPR_ASSERTING_INT_CAST(
size_t, diff));
856 rc = _snprintf(&dst[pos], WINPR_ASSERTING_INT_CAST(
size_t, diff + 1),
"%s", tmp);
862 rc = _snprintf(&dst[pos], 4,
"%%%x", *stop_at);
867 previous_at = stop_at + 1;
870 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s", previous_at, lineending);
874 if ((rc < 0) || fail)
883 if (skip_last_lineending)
885 const size_t endlen = strlen(lineending);
888 const size_t len = strnlen(dst, alloc);
895 if (memcmp(&dst[len - endlen], lineending, endlen) == 0)
897 memset(&dst[len - endlen], 0, endlen);
903 alloc = strnlen(dst, alloc) + 1;
904 *pSize = (UINT32)alloc;
905 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
915WINPR_ATTR_MALLOC(free, 1)
916static
void* convert_filedescriptors_to_uri_list(wClipboard* clipboard, UINT32 formatId,
917 const
void* data, UINT32* pSize)
919 if (formatId != ClipboardGetFormatId(clipboard, mime_uri_list))
922 "Unuspported destination format %s [0x%04" PRIx32
923 "], trying to convert from %s [0x%04" PRIx32
"]",
924 ClipboardGetFormatName(clipboard, formatId), formatId,
925 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
928 if (clipboard->formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
931 "Unuspported destination format %s [0x%04" PRIx32
932 "], trying to convert from %s [0x%04" PRIx32
"]",
933 ClipboardGetFormatName(clipboard, formatId), formatId,
934 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
937 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"",
"file://",
942WINPR_ATTR_MALLOC(free, 1)
943static
void* convert_filedescriptors_to_gnome_copied_files(wClipboard* clipboard, UINT32 formatId,
944 const
void* data, UINT32* pSize)
946 if (formatId != ClipboardGetFormatId(clipboard, mime_gnome_copied_files))
949 "Unuspported destination format %s [0x%04" PRIx32
950 "], trying to convert from %s [0x%04" PRIx32
"]",
951 ClipboardGetFormatName(clipboard, formatId), formatId,
952 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
955 if (clipboard->formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
958 "Unuspported destination format %s [0x%04" PRIx32
959 "], trying to convert from %s [0x%04" PRIx32
"]",
960 ClipboardGetFormatName(clipboard, formatId), formatId,
961 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
964 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"copy\n",
965 "file://",
"\n", TRUE);
968WINPR_ATTR_MALLOC(free, 1)
969static
void* convert_filedescriptors_to_mate_copied_files(wClipboard* clipboard, UINT32 formatId,
970 const
void* data, UINT32* pSize)
972 if (formatId != ClipboardGetFormatId(clipboard, mime_mate_copied_files))
975 "Unuspported destination format %s [0x%04" PRIx32
976 "], trying to convert from %s [0x%04" PRIx32
"]",
977 ClipboardGetFormatName(clipboard, formatId), formatId,
978 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
981 if (clipboard->formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
984 "Unuspported destination format %s [0x%04" PRIx32
985 "], trying to convert from %s [0x%04" PRIx32
"]",
986 ClipboardGetFormatName(clipboard, formatId), formatId,
987 ClipboardGetFormatName(clipboard, clipboard->formatId), clipboard->formatId);
990 char* pDstData = convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
991 "copy\n",
"file://",
"\n", TRUE);
1001 pDstData[*pSize - 1] =
'\0';
1002 *pSize = *pSize - 1;
1006static void array_free_synthetic_file(
void* the_file)
1008 struct synthetic_file* file = the_file;
1009 free_synthetic_file(file);
1012static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard)
1037 const UINT32 local_gnome_file_format_id =
1038 ClipboardRegisterFormat(clipboard, mime_gnome_copied_files);
1039 const UINT32 local_mate_file_format_id =
1040 ClipboardRegisterFormat(clipboard, mime_mate_copied_files);
1041 const UINT32 file_group_format_id =
1042 ClipboardRegisterFormat(clipboard, mime_FileGroupDescriptorW);
1043 const UINT32 local_file_format_id = ClipboardRegisterFormat(clipboard, mime_uri_list);
1045 if (!file_group_format_id || !local_file_format_id || !local_gnome_file_format_id ||
1046 !local_mate_file_format_id)
1049 clipboard->localFiles = ArrayList_New(FALSE);
1051 if (!clipboard->localFiles)
1054 obj = ArrayList_Object(clipboard->localFiles);
1057 if (!ClipboardRegisterSynthesizerEx(clipboard, local_file_format_id, file_group_format_id,
1058 convert_uri_list_to_filedescriptors))
1059 goto error_free_local_files;
1061 if (!ClipboardRegisterSynthesizerEx(clipboard, file_group_format_id, local_file_format_id,
1062 convert_filedescriptors_to_uri_list))
1063 goto error_free_local_files;
1065 if (!ClipboardRegisterSynthesizerEx(clipboard, local_gnome_file_format_id, file_group_format_id,
1066 convert_gnome_copied_files_to_filedescriptors))
1067 goto error_free_local_files;
1069 if (!ClipboardRegisterSynthesizerEx(clipboard, file_group_format_id, local_gnome_file_format_id,
1070 convert_filedescriptors_to_gnome_copied_files))
1071 goto error_free_local_files;
1073 if (!ClipboardRegisterSynthesizerEx(clipboard, local_mate_file_format_id, file_group_format_id,
1074 convert_mate_copied_files_to_filedescriptors))
1075 goto error_free_local_files;
1077 if (!ClipboardRegisterSynthesizerEx(clipboard, file_group_format_id, local_mate_file_format_id,
1078 convert_filedescriptors_to_mate_copied_files))
1079 goto error_free_local_files;
1082error_free_local_files:
1083 ArrayList_Free(clipboard->localFiles);
1084 clipboard->localFiles =
nullptr;
1089static int32_t file_get_size(
const struct synthetic_file* file, UINT64* size)
1094 return E_INVALIDARG;
1096 s = file->nFileSizeHigh;
1098 s |= file->nFileSizeLow;
1103static UINT delegate_file_request_size(wClipboardDelegate* delegate,
1108 if (!delegate || !delegate->clipboard || !request)
1109 return ERROR_BAD_ARGUMENTS;
1111 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1112 return ERROR_INVALID_STATE;
1114 struct synthetic_file* file =
1115 ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1118 return ERROR_INDEX_ABSENT;
1120 const int32_t s = file_get_size(file, &size);
1123 error = delegate->ClipboardFileSizeFailure(delegate, request, (UINT)s);
1125 error = delegate->ClipboardFileSizeSuccess(delegate, request, size);
1128 WLog_WARN(TAG,
"failed to report file size result: 0x%08X", error);
1133UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force)
1135 if (!file || INVALID_HANDLE_VALUE == file->fd)
1141 file_get_size(file, &size);
1142 if ((file->offset < 0) || ((UINT64)file->offset >= size) || force)
1144 WLog_VRB(TAG,
"close file %p", file->fd);
1145 if (!CloseHandle(file->fd))
1147 WLog_WARN(TAG,
"failed to close fd %p: %" PRIu32, file->fd, GetLastError());
1150 file->fd = INVALID_HANDLE_VALUE;
1156static UINT file_get_range(
struct synthetic_file* file, UINT64 offset, UINT32 size,
1157 BYTE** actual_data, UINT32* actual_size)
1159 UINT error = NO_ERROR;
1164 WINPR_ASSERT(actual_data);
1165 WINPR_ASSERT(actual_size);
1167 if (INVALID_HANDLE_VALUE == file->fd)
1171 file->fd = CreateFileW(file->local_name, GENERIC_READ, 0,
nullptr, OPEN_EXISTING,
1172 FILE_ATTRIBUTE_NORMAL,
nullptr);
1173 if (INVALID_HANDLE_VALUE == file->fd)
1175 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
1176 ConvertWCharToUtf8(file->local_name, name,
sizeof(name) - 1);
1177 error = GetLastError();
1178 WLog_ERR(TAG,
"failed to open file %s: 0x%08" PRIx32, name, error);
1182 if (!GetFileInformationByHandle(file->fd, &FileInfo))
1184 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
1185 ConvertWCharToUtf8(file->local_name, name,
sizeof(name) - 1);
1186 (void)CloseHandle(file->fd);
1187 file->fd = INVALID_HANDLE_VALUE;
1188 error = GetLastError();
1189 WLog_ERR(TAG,
"Get file [%s] information fail: 0x%08" PRIx32, name, error);
1194 file->nFileSizeHigh = FileInfo.nFileSizeHigh;
1195 file->nFileSizeLow = FileInfo.nFileSizeLow;
1214 if (offset > INT64_MAX)
1216 WLog_ERR(TAG,
"offset [%" PRIu64
"] > INT64_MAX", offset);
1221 if (file->offset != (INT64)offset)
1223 WLog_DBG(TAG,
"file %p force seeking to %" PRIu64
", current %" PRId64, file->fd,
1224 offset, file->offset);
1226 dwHigh = offset >> 32;
1227 dwLow = offset & 0xFFFFFFFF;
1228 if (INVALID_SET_FILE_POINTER == SetFilePointer(file->fd,
1229 WINPR_ASSERTING_INT_CAST(LONG, dwLow),
1230 (PLONG)&dwHigh, FILE_BEGIN))
1232 error = GetLastError();
1237 BYTE* buffer = malloc(size);
1240 error = ERROR_NOT_ENOUGH_MEMORY;
1243 if (!ReadFile(file->fd, buffer, size, (LPDWORD)actual_size,
nullptr))
1246 error = GetLastError();
1250 *actual_data = buffer;
1251 file->offset += *actual_size;
1252 WLog_VRB(TAG,
"file %p actual read %" PRIu32
" bytes (offset %" PRId64
")", file->fd,
1253 *actual_size, file->offset);
1256 synthetic_file_read_close(file, TRUE );
1260static UINT delegate_file_request_range(wClipboardDelegate* delegate,
1264 BYTE* data =
nullptr;
1267 struct synthetic_file* file =
nullptr;
1269 if (!delegate || !delegate->clipboard || !request)
1270 return ERROR_BAD_ARGUMENTS;
1272 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1273 return ERROR_INVALID_STATE;
1275 file = ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1278 return ERROR_INDEX_ABSENT;
1280 offset = (((UINT64)request->nPositionHigh) << 32) | ((UINT64)request->nPositionLow);
1281 error = file_get_range(file, offset, request->cbRequested, &data, &size);
1284 error = delegate->ClipboardFileRangeFailure(delegate, request, error);
1286 error = delegate->ClipboardFileRangeSuccess(delegate, request, data, size);
1289 WLog_WARN(TAG,
"failed to report file range result: 0x%08X", error);
1295static UINT dummy_file_size_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1297 WINPR_ATTR_UNUSED UINT64 fileSize)
1299 return ERROR_NOT_SUPPORTED;
1302static UINT dummy_file_size_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1304 WINPR_ATTR_UNUSED UINT errorCode)
1306 return ERROR_NOT_SUPPORTED;
1309static UINT dummy_file_range_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1311 WINPR_ATTR_UNUSED
const BYTE* data,
1312 WINPR_ATTR_UNUSED UINT32 size)
1314 return ERROR_NOT_SUPPORTED;
1317static UINT dummy_file_range_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1319 WINPR_ATTR_UNUSED UINT errorCode)
1321 return ERROR_NOT_SUPPORTED;
1324static void setup_delegate(wClipboardDelegate* delegate)
1326 WINPR_ASSERT(delegate);
1328 delegate->ClientRequestFileSize = delegate_file_request_size;
1329 delegate->ClipboardFileSizeSuccess = dummy_file_size_success;
1330 delegate->ClipboardFileSizeFailure = dummy_file_size_failure;
1331 delegate->ClientRequestFileRange = delegate_file_request_range;
1332 delegate->ClipboardFileRangeSuccess = dummy_file_range_success;
1333 delegate->ClipboardFileRangeFailure = dummy_file_range_failure;
1334 delegate->IsFileNameComponentValid = ValidFileNameComponent;
1337BOOL ClipboardInitSyntheticFileSubsystem(wClipboard* clipboard)
1342 if (!register_file_formats_and_synthesizers(clipboard))
1345 setup_delegate(&clipboard->delegate);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree