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 = NULL;
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)
105 const size_t len = _wcslen(file->remote_name);
106 PathCchConvertStyleW(file->remote_name, len, PATH_STYLE_WINDOWS);
108 file->dwFileAttributes = fd.dwFileAttributes;
109 file->ftCreationTime = fd.ftCreationTime;
110 file->ftLastWriteTime = fd.ftLastWriteTime;
111 file->ftLastAccessTime = fd.ftLastAccessTime;
112 file->nFileSizeHigh = fd.nFileSizeHigh;
113 file->nFileSizeLow = fd.nFileSizeLow;
117 free_synthetic_file(file);
121static UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force);
123void free_synthetic_file(
struct synthetic_file* file)
128 synthetic_file_read_close(file, TRUE);
130 free(file->local_name);
131 free(file->remote_name);
139static WCHAR* convert_local_name_component_to_remote(wClipboard* clipboard,
const WCHAR* local_name)
141 wClipboardDelegate* delegate = ClipboardGetDelegate(clipboard);
142 WCHAR* remote_name = NULL;
144 WINPR_ASSERT(delegate);
146 remote_name = _wcsdup(local_name);
157 if (!delegate->IsFileNameComponentValid(remote_name))
159 WLog_ERR(TAG,
"invalid file name component: %s", local_name);
169static WCHAR* concat_file_name(
const WCHAR* dir,
const WCHAR* file)
173 const WCHAR slash =
'/';
174 WCHAR* buffer = NULL;
179 len_dir = _wcslen(dir);
180 len_file = _wcslen(file);
181 buffer = calloc(len_dir + 1 + len_file + 2,
sizeof(WCHAR));
186 memcpy(buffer, dir, len_dir *
sizeof(WCHAR));
187 buffer[len_dir] = slash;
188 memcpy(buffer + len_dir + 1, file, len_file *
sizeof(WCHAR));
192static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
193 const WCHAR* remote_name, wArrayList* files);
195static BOOL add_directory_entry_to_list(wClipboard* clipboard,
const WCHAR* local_dir_name,
196 const WCHAR* remote_dir_name,
200 WCHAR* local_name = NULL;
201 WCHAR* remote_name = NULL;
202 WCHAR* remote_base_name = NULL;
204 WCHAR dotbuffer[6] = { 0 };
205 WCHAR dotdotbuffer[6] = { 0 };
206 const WCHAR* dot = InitializeConstWCharFromUtf8(
".", dotbuffer, ARRAYSIZE(dotbuffer));
207 const WCHAR* dotdot = InitializeConstWCharFromUtf8(
"..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
209 WINPR_ASSERT(clipboard);
210 WINPR_ASSERT(local_dir_name);
211 WINPR_ASSERT(remote_dir_name);
212 WINPR_ASSERT(pFileData);
217 if ((_wcscmp(pFileData->cFileName, dot) == 0) || (_wcscmp(pFileData->cFileName, dotdot) == 0))
220 remote_base_name = convert_local_name_component_to_remote(clipboard, pFileData->cFileName);
222 if (!remote_base_name)
225 local_name = concat_file_name(local_dir_name, pFileData->cFileName);
226 remote_name = concat_file_name(remote_dir_name, remote_base_name);
228 if (local_name && remote_name)
229 result = add_file_to_list(clipboard, local_name, remote_name, files);
231 free(remote_base_name);
237static BOOL do_add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
238 const WCHAR* remote_name, WCHAR* namebuf,
241 WINPR_ASSERT(clipboard);
242 WINPR_ASSERT(local_name);
243 WINPR_ASSERT(remote_name);
245 WINPR_ASSERT(namebuf);
248 HANDLE hFind = FindFirstFileW(namebuf, &FindData);
249 if (INVALID_HANDLE_VALUE == hFind)
251 WLog_ERR(TAG,
"FindFirstFile failed (%" PRIu32
")", GetLastError());
256 if (!add_directory_entry_to_list(clipboard, local_name, remote_name, &FindData, files))
262 BOOL bRet = FindNextFileW(hFind, &FindData);
266 if (ERROR_NO_MORE_FILES == GetLastError())
268 WLog_WARN(TAG,
"FindNextFile failed (%" PRIu32
")", GetLastError());
276static BOOL add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
277 const WCHAR* remote_name, wArrayList* files)
285 const char buffer[6] =
"/\0*\0\0\0";
287 const size_t wildcardLen = ARRAYSIZE(buffer) /
sizeof(WCHAR);
289 WINPR_ASSERT(clipboard);
290 WINPR_ASSERT(local_name);
291 WINPR_ASSERT(remote_name);
294 size_t len = _wcslen(local_name);
295 WCHAR* namebuf = calloc(len + wildcardLen,
sizeof(WCHAR));
299 _wcsncat(namebuf, local_name, len);
300 _wcsncat(namebuf, wildcard.w, wildcardLen);
302 result = do_add_directory_contents_to_list(clipboard, local_name, remote_name, namebuf, files);
308static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
309 const WCHAR* remote_name, wArrayList* files)
311 struct synthetic_file* file = NULL;
313 WINPR_ASSERT(clipboard);
314 WINPR_ASSERT(local_name);
315 WINPR_ASSERT(remote_name);
318 file = make_synthetic_file(local_name, remote_name);
323 if (!ArrayList_Append(files, file))
325 free_synthetic_file(file);
329 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
335 if (!add_directory_contents_to_list(clipboard, local_name, remote_name, files))
342static const WCHAR* get_basename(
const WCHAR* name)
344 const WCHAR* c = name;
345 const WCHAR* last_name = name;
346 const WCHAR slash =
'/';
359static BOOL process_file_name(wClipboard* clipboard,
const WCHAR* local_name, wArrayList* files)
362 const WCHAR* base_name = NULL;
363 WCHAR* remote_name = NULL;
365 WINPR_ASSERT(clipboard);
366 WINPR_ASSERT(local_name);
374 base_name = get_basename(local_name);
375 remote_name = convert_local_name_component_to_remote(clipboard, base_name);
380 result = add_file_to_list(clipboard, local_name, remote_name, files);
385static BOOL process_uri(wClipboard* clipboard,
const char* uri,
size_t uri_len)
391 WINPR_ASSERT(clipboard);
393 name = parse_uri_to_local_file(uri, uri_len);
404 wname = ConvertUtf8ToWCharAlloc(name, NULL);
406 result = process_file_name(clipboard, wname, clipboard->localFiles);
415static BOOL process_uri_list(wClipboard* clipboard,
const char* data,
size_t length)
417 const char* cur = data;
418 const char* lim = data + length;
420 WINPR_ASSERT(clipboard);
423 WLog_VRB(TAG,
"processing URI list:\n%.*s", length, data);
424 ArrayList_Clear(clipboard->localFiles);
436 BOOL comment = (*cur ==
'#');
437 const char* start = cur;
438 const char* stop = cur;
440 for (; stop < lim; stop++)
444 if ((stop + 1 < lim) && (*(stop + 1) ==
'\n'))
461 if (strnlen(start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)) < 1)
469 if (!process_uri(clipboard, start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)))
476static BOOL convert_local_file_to_filedescriptor(
const struct synthetic_file* file,
479 size_t remote_len = 0;
482 WINPR_ASSERT(descriptor);
484 descriptor->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI;
486 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
488 descriptor->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
489 descriptor->nFileSizeLow = 0;
490 descriptor->nFileSizeHigh = 0;
494 descriptor->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
495 descriptor->nFileSizeLow = file->nFileSizeLow;
496 descriptor->nFileSizeHigh = file->nFileSizeHigh;
499 descriptor->ftLastWriteTime = file->ftLastWriteTime;
501 remote_len = _wcsnlen(file->remote_name, ARRAYSIZE(descriptor->cFileName));
503 if (remote_len >= ARRAYSIZE(descriptor->cFileName))
505 WLog_ERR(TAG,
"file name too long (%" PRIuz
" characters)", remote_len);
509 memcpy(descriptor->cFileName, file->remote_name, remote_len *
sizeof(WCHAR));
513static FILEDESCRIPTORW* convert_local_file_list_to_filedescriptors(wArrayList* files)
518 count = ArrayList_Count(files);
525 for (
size_t i = 0; i < count; i++)
527 const struct synthetic_file* file = ArrayList_GetItem(files, i);
529 if (!convert_local_file_to_filedescriptor(file, &descriptors[i]))
539static void* convert_any_uri_list_to_filedescriptors(wClipboard* clipboard,
540 WINPR_ATTR_UNUSED UINT32 formatId,
545 WINPR_ASSERT(clipboard);
548 descriptors = convert_local_file_list_to_filedescriptors(clipboard->localFiles);
553 *pSize = (UINT32)ArrayList_Count(clipboard->localFiles) *
sizeof(
FILEDESCRIPTORW);
554 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
558static void* convert_uri_list_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
559 const void* data, UINT32* pSize)
561 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_uri_list);
562 if (formatId != expected)
564 if (!process_uri_list(clipboard, (
const char*)data, *pSize))
566 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
569static BOOL process_files(wClipboard* clipboard,
const char* data, UINT32 pSize,
const char* prefix)
571 WINPR_ASSERT(prefix);
573 const size_t prefix_len = strlen(prefix);
575 WINPR_ASSERT(clipboard);
577 ArrayList_Clear(clipboard->localFiles);
579 if (!data || (pSize < prefix_len))
581 if (strncmp(data, prefix, prefix_len) != 0)
584 if (pSize < prefix_len)
586 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, prefix_len);
589 char* copy = strndup(data, pSize);
594 char* tok = strtok_s(copy,
"\n", &endptr);
597 const size_t tok_len = strnlen(tok, pSize);
598 if (!process_uri(clipboard, tok, tok_len))
602 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, tok_len);
603 tok = strtok_s(NULL,
"\n", &endptr);
612static BOOL process_gnome_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
614 return process_files(clipboard, data, pSize,
"copy\n");
617static BOOL process_mate_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
619 return process_files(clipboard, data, pSize,
"copy\n");
622static void* convert_gnome_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
623 const void* data, UINT32* pSize)
625 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_gnome_copied_files);
626 if (formatId != expected)
628 if (!process_gnome_copied_files(clipboard, (
const char*)data, *pSize))
630 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
633static void* convert_mate_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
634 const void* data, UINT32* pSize)
636 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_mate_copied_files);
637 if (formatId != expected)
640 if (!process_mate_copied_files(clipboard, (
const char*)data, *pSize))
643 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
646static size_t count_special_chars(
const WCHAR* str)
649 const WCHAR* start = str;
654 const WCHAR sharp =
'#';
655 const WCHAR questionmark =
'?';
656 const WCHAR star =
'*';
657 const WCHAR exclamationmark =
'!';
658 const WCHAR percent =
'%';
660 if ((*start == sharp) || (*start == questionmark) || (*start == star) ||
661 (*start == exclamationmark) || (*start == percent))
670static const char* stop_at_special_chars(
const char* str)
672 const char* start = str;
677 if (*start ==
'#' || *start ==
'?' || *start ==
'*' || *start ==
'!' || *start ==
'%')
687static void* convert_filedescriptors_to_file_list(wClipboard* clipboard, UINT32 formatId,
688 const void* data, UINT32* pSize,
689 const char* header,
const char* lineprefix,
690 const char* lineending, BOOL skip_last_lineending)
697 backslash.c[0] =
'\\';
698 backslash.c[1] =
'\0';
701 UINT32 nrDescriptors = 0;
705 size_t baseLength = 0;
707 size_t header_len = strlen(header);
708 size_t lineprefix_len = strlen(lineprefix);
709 size_t lineending_len = strlen(lineending);
710 size_t decoration_len = 0;
712 if (!clipboard || !data || !pSize)
715 if (*pSize <
sizeof(UINT32))
718 if (clipboard->delegate.basePath)
719 baseLength = strnlen(clipboard->delegate.basePath, MAX_PATH);
725 wStream* s = Stream_StaticConstInit(&sbuffer, data, *pSize);
726 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
729 Stream_Read_UINT32(s, nrDescriptors);
733 if ((count < 1) || (count != nrDescriptors))
736 descriptors = Stream_ConstPointer(s);
738 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
742 decoration_len = lineprefix_len + lineending_len + baseLength + 1;
746 for (
size_t x = 0; x < count; x++)
750 if (_wcschr(dsc->cFileName, backslash.w) == NULL)
752 alloc += ARRAYSIZE(dsc->cFileName) *
755 alloc += count_special_chars(dsc->cFileName) * 2;
756 alloc += decoration_len;
763 dst = calloc(alloc,
sizeof(
char));
768 (void)_snprintf(&dst[0], alloc,
"%s", header);
772 for (
size_t x = 0; x < count; x++)
776 if (_wcschr(dsc->cFileName, backslash.w) != NULL)
781 char curName[520] = { 0 };
782 const char* stop_at = NULL;
783 const char* previous_at = NULL;
785 if (ConvertWCharNToUtf8(dsc->cFileName, ARRAYSIZE(dsc->cFileName), curName,
786 ARRAYSIZE(curName)) < 0)
789 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s/", lineprefix, clipboard->delegate.basePath);
796 previous_at = curName;
797 while ((stop_at = stop_at_special_chars(previous_at)) != NULL)
799 const intptr_t diff = stop_at - previous_at;
802 char* tmp = strndup(previous_at, WINPR_ASSERTING_INT_CAST(
size_t, diff));
806 rc = _snprintf(&dst[pos], WINPR_ASSERTING_INT_CAST(
size_t, diff + 1),
"%s", tmp);
812 rc = _snprintf(&dst[pos], 4,
"%%%x", *stop_at);
817 previous_at = stop_at + 1;
820 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s", previous_at, lineending);
824 if ((rc < 0) || fail)
833 if (skip_last_lineending)
835 const size_t endlen = strlen(lineending);
838 const size_t len = strnlen(dst, alloc);
845 if (memcmp(&dst[len - endlen], lineending, endlen) == 0)
847 memset(&dst[len - endlen], 0, endlen);
853 alloc = strnlen(dst, alloc) + 1;
854 *pSize = (UINT32)alloc;
855 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
865static void* convert_filedescriptors_to_uri_list(wClipboard* clipboard, UINT32 formatId,
866 const void* data, UINT32* pSize)
868 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"",
"file://",
873static void* convert_filedescriptors_to_gnome_copied_files(wClipboard* clipboard, UINT32 formatId,
874 const void* data, UINT32* pSize)
876 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"copy\n",
877 "file://",
"\n", TRUE);
880static void* convert_filedescriptors_to_mate_copied_files(wClipboard* clipboard, UINT32 formatId,
881 const void* data, UINT32* pSize)
884 char* pDstData = convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
885 "copy\n",
"file://",
"\n", TRUE);
895 pDstData[*pSize - 1] =
'\0';
900static void array_free_synthetic_file(
void* the_file)
902 struct synthetic_file* file = the_file;
903 free_synthetic_file(file);
906static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard)
931 const UINT32 local_gnome_file_format_id =
932 ClipboardRegisterFormat(clipboard, mime_gnome_copied_files);
933 const UINT32 local_mate_file_format_id =
934 ClipboardRegisterFormat(clipboard, mime_mate_copied_files);
935 const UINT32 file_group_format_id =
936 ClipboardRegisterFormat(clipboard, mime_FileGroupDescriptorW);
937 const UINT32 local_file_format_id = ClipboardRegisterFormat(clipboard, mime_uri_list);
939 if (!file_group_format_id || !local_file_format_id || !local_gnome_file_format_id ||
940 !local_mate_file_format_id)
943 clipboard->localFiles = ArrayList_New(FALSE);
945 if (!clipboard->localFiles)
948 obj = ArrayList_Object(clipboard->localFiles);
949 obj->fnObjectFree = array_free_synthetic_file;
951 if (!ClipboardRegisterSynthesizer(clipboard, local_file_format_id, file_group_format_id,
952 convert_uri_list_to_filedescriptors))
953 goto error_free_local_files;
955 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_file_format_id,
956 convert_filedescriptors_to_uri_list))
957 goto error_free_local_files;
959 if (!ClipboardRegisterSynthesizer(clipboard, local_gnome_file_format_id, file_group_format_id,
960 convert_gnome_copied_files_to_filedescriptors))
961 goto error_free_local_files;
963 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_gnome_file_format_id,
964 convert_filedescriptors_to_gnome_copied_files))
965 goto error_free_local_files;
967 if (!ClipboardRegisterSynthesizer(clipboard, local_mate_file_format_id, file_group_format_id,
968 convert_mate_copied_files_to_filedescriptors))
969 goto error_free_local_files;
971 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_mate_file_format_id,
972 convert_filedescriptors_to_mate_copied_files))
973 goto error_free_local_files;
976error_free_local_files:
977 ArrayList_Free(clipboard->localFiles);
978 clipboard->localFiles = NULL;
983static int32_t file_get_size(
const struct synthetic_file* file, UINT64* size)
990 s = file->nFileSizeHigh;
992 s |= file->nFileSizeLow;
997static UINT delegate_file_request_size(wClipboardDelegate* delegate,
1002 if (!delegate || !delegate->clipboard || !request)
1003 return ERROR_BAD_ARGUMENTS;
1005 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1006 return ERROR_INVALID_STATE;
1008 struct synthetic_file* file =
1009 ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1012 return ERROR_INDEX_ABSENT;
1014 const int32_t s = file_get_size(file, &size);
1017 error = delegate->ClipboardFileSizeFailure(delegate, request, (UINT)s);
1019 error = delegate->ClipboardFileSizeSuccess(delegate, request, size);
1022 WLog_WARN(TAG,
"failed to report file size result: 0x%08X", error);
1027UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force)
1029 if (!file || INVALID_HANDLE_VALUE == file->fd)
1035 file_get_size(file, &size);
1036 if ((file->offset < 0) || ((UINT64)file->offset >= size) || force)
1038 WLog_VRB(TAG,
"close file %d", file->fd);
1039 if (!CloseHandle(file->fd))
1041 WLog_WARN(TAG,
"failed to close fd %d: %" PRIu32, file->fd, GetLastError());
1044 file->fd = INVALID_HANDLE_VALUE;
1050static UINT file_get_range(
struct synthetic_file* file, UINT64 offset, UINT32 size,
1051 BYTE** actual_data, UINT32* actual_size)
1053 UINT error = NO_ERROR;
1058 WINPR_ASSERT(actual_data);
1059 WINPR_ASSERT(actual_size);
1061 if (INVALID_HANDLE_VALUE == file->fd)
1065 file->fd = CreateFileW(file->local_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1066 FILE_ATTRIBUTE_NORMAL, NULL);
1067 if (INVALID_HANDLE_VALUE == file->fd)
1069 error = GetLastError();
1070 WLog_ERR(TAG,
"failed to open file %s: 0x%08" PRIx32, file->local_name, error);
1074 if (!GetFileInformationByHandle(file->fd, &FileInfo))
1076 (void)CloseHandle(file->fd);
1077 file->fd = INVALID_HANDLE_VALUE;
1078 error = GetLastError();
1079 WLog_ERR(TAG,
"Get file [%s] information fail: 0x%08" PRIx32, file->local_name, error);
1084 file->nFileSizeHigh = FileInfo.nFileSizeHigh;
1085 file->nFileSizeLow = FileInfo.nFileSizeLow;
1104 if (offset > INT64_MAX)
1106 WLog_ERR(TAG,
"offset [%" PRIu64
"] > INT64_MAX", offset);
1111 if (file->offset != (INT64)offset)
1113 WLog_DBG(TAG,
"file %d force seeking to %" PRIu64
", current %" PRIu64, file->fd,
1114 offset, file->offset);
1116 dwHigh = offset >> 32;
1117 dwLow = offset & 0xFFFFFFFF;
1118 if (INVALID_SET_FILE_POINTER == SetFilePointer(file->fd,
1119 WINPR_ASSERTING_INT_CAST(LONG, dwLow),
1120 (PLONG)&dwHigh, FILE_BEGIN))
1122 error = GetLastError();
1127 BYTE* buffer = malloc(size);
1130 error = ERROR_NOT_ENOUGH_MEMORY;
1133 if (!ReadFile(file->fd, buffer, size, (LPDWORD)actual_size, NULL))
1136 error = GetLastError();
1140 *actual_data = buffer;
1141 file->offset += *actual_size;
1142 WLog_VRB(TAG,
"file %d actual read %" PRIu32
" bytes (offset %" PRIu64
")", file->fd,
1143 *actual_size, file->offset);
1146 synthetic_file_read_close(file, TRUE );
1150static UINT delegate_file_request_range(wClipboardDelegate* delegate,
1157 struct synthetic_file* file = NULL;
1159 if (!delegate || !delegate->clipboard || !request)
1160 return ERROR_BAD_ARGUMENTS;
1162 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1163 return ERROR_INVALID_STATE;
1165 file = ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1168 return ERROR_INDEX_ABSENT;
1170 offset = (((UINT64)request->nPositionHigh) << 32) | ((UINT64)request->nPositionLow);
1171 error = file_get_range(file, offset, request->cbRequested, &data, &size);
1174 error = delegate->ClipboardFileRangeFailure(delegate, request, error);
1176 error = delegate->ClipboardFileRangeSuccess(delegate, request, data, size);
1179 WLog_WARN(TAG,
"failed to report file range result: 0x%08X", error);
1185static UINT dummy_file_size_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1187 WINPR_ATTR_UNUSED UINT64 fileSize)
1189 return ERROR_NOT_SUPPORTED;
1192static UINT dummy_file_size_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1194 WINPR_ATTR_UNUSED UINT errorCode)
1196 return ERROR_NOT_SUPPORTED;
1199static UINT dummy_file_range_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1201 WINPR_ATTR_UNUSED
const BYTE* data,
1202 WINPR_ATTR_UNUSED UINT32 size)
1204 return ERROR_NOT_SUPPORTED;
1207static UINT dummy_file_range_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1209 WINPR_ATTR_UNUSED UINT errorCode)
1211 return ERROR_NOT_SUPPORTED;
1214static void setup_delegate(wClipboardDelegate* delegate)
1216 WINPR_ASSERT(delegate);
1218 delegate->ClientRequestFileSize = delegate_file_request_size;
1219 delegate->ClipboardFileSizeSuccess = dummy_file_size_success;
1220 delegate->ClipboardFileSizeFailure = dummy_file_size_failure;
1221 delegate->ClientRequestFileRange = delegate_file_request_range;
1222 delegate->ClipboardFileRangeSuccess = dummy_file_range_success;
1223 delegate->ClipboardFileRangeFailure = dummy_file_range_failure;
1224 delegate->IsFileNameComponentValid = ValidFileNameComponent;
1227BOOL ClipboardInitSyntheticFileSubsystem(wClipboard* clipboard)
1232 if (!register_file_formats_and_synthesizers(clipboard))
1235 setup_delegate(&clipboard->delegate);
This struct contains function pointer to initialize/free objects.