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)
106 const size_t len = _wcslen(file->remote_name);
107 PathCchConvertStyleW(file->remote_name, len, PATH_STYLE_WINDOWS);
110 file->dwFileAttributes = fd.dwFileAttributes;
111 file->ftCreationTime = fd.ftCreationTime;
112 file->ftLastWriteTime = fd.ftLastWriteTime;
113 file->ftLastAccessTime = fd.ftLastAccessTime;
114 file->nFileSizeHigh = fd.nFileSizeHigh;
115 file->nFileSizeLow = fd.nFileSizeLow;
119 free_synthetic_file(file);
123static UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force);
125void free_synthetic_file(
struct synthetic_file* file)
130 synthetic_file_read_close(file, TRUE);
132 free(file->local_name);
133 free(file->remote_name);
141static WCHAR* convert_local_name_component_to_remote(wClipboard* clipboard,
const WCHAR* local_name)
143 wClipboardDelegate* delegate = ClipboardGetDelegate(clipboard);
144 WCHAR* remote_name = NULL;
146 WINPR_ASSERT(delegate);
148 remote_name = _wcsdup(local_name);
159 if (!delegate->IsFileNameComponentValid(remote_name))
161 WLog_ERR(TAG,
"invalid file name component: %s", local_name);
171static WCHAR* concat_file_name(
const WCHAR* dir,
const WCHAR* file)
175 const WCHAR slash =
'/';
176 WCHAR* buffer = NULL;
181 len_dir = _wcslen(dir);
182 len_file = _wcslen(file);
183 buffer = calloc(len_dir + 1 + len_file + 2,
sizeof(WCHAR));
188 memcpy(buffer, dir, len_dir *
sizeof(WCHAR));
189 buffer[len_dir] = slash;
190 memcpy(buffer + len_dir + 1, file, len_file *
sizeof(WCHAR));
194static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
195 const WCHAR* remote_name, wArrayList* files);
197static BOOL add_directory_entry_to_list(wClipboard* clipboard,
const WCHAR* local_dir_name,
198 const WCHAR* remote_dir_name,
202 WCHAR* local_name = NULL;
203 WCHAR* remote_name = NULL;
204 WCHAR* remote_base_name = NULL;
206 WCHAR dotbuffer[6] = { 0 };
207 WCHAR dotdotbuffer[6] = { 0 };
208 const WCHAR* dot = InitializeConstWCharFromUtf8(
".", dotbuffer, ARRAYSIZE(dotbuffer));
209 const WCHAR* dotdot = InitializeConstWCharFromUtf8(
"..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
211 WINPR_ASSERT(clipboard);
212 WINPR_ASSERT(local_dir_name);
213 WINPR_ASSERT(remote_dir_name);
214 WINPR_ASSERT(pFileData);
219 if ((_wcscmp(pFileData->cFileName, dot) == 0) || (_wcscmp(pFileData->cFileName, dotdot) == 0))
222 remote_base_name = convert_local_name_component_to_remote(clipboard, pFileData->cFileName);
224 if (!remote_base_name)
227 local_name = concat_file_name(local_dir_name, pFileData->cFileName);
228 remote_name = concat_file_name(remote_dir_name, remote_base_name);
230 if (local_name && remote_name)
231 result = add_file_to_list(clipboard, local_name, remote_name, files);
233 free(remote_base_name);
239static BOOL do_add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
240 const WCHAR* remote_name, WCHAR* namebuf,
243 WINPR_ASSERT(clipboard);
244 WINPR_ASSERT(local_name);
245 WINPR_ASSERT(remote_name);
247 WINPR_ASSERT(namebuf);
250 HANDLE hFind = FindFirstFileW(namebuf, &FindData);
251 if (INVALID_HANDLE_VALUE == hFind)
253 WLog_ERR(TAG,
"FindFirstFile failed (%" PRIu32
")", GetLastError());
258 if (!add_directory_entry_to_list(clipboard, local_name, remote_name, &FindData, files))
264 BOOL bRet = FindNextFileW(hFind, &FindData);
268 if (ERROR_NO_MORE_FILES == GetLastError())
270 WLog_WARN(TAG,
"FindNextFile failed (%" PRIu32
")", GetLastError());
278static BOOL add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
279 const WCHAR* remote_name, wArrayList* files)
287 const char buffer[6] = {
'/',
'\0',
'*',
'\0',
'\0',
'\0' };
289 const size_t wildcardLen = ARRAYSIZE(buffer) /
sizeof(WCHAR);
291 WINPR_ASSERT(clipboard);
292 WINPR_ASSERT(local_name);
293 WINPR_ASSERT(remote_name);
296 size_t len = _wcslen(local_name);
297 WCHAR* namebuf = calloc(len + wildcardLen,
sizeof(WCHAR));
301 _wcsncat(namebuf, local_name, len);
302 _wcsncat(namebuf, wildcard.w, wildcardLen);
304 result = do_add_directory_contents_to_list(clipboard, local_name, remote_name, namebuf, files);
310static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
311 const WCHAR* remote_name, wArrayList* files)
313 struct synthetic_file* file = NULL;
315 WINPR_ASSERT(clipboard);
316 WINPR_ASSERT(local_name);
317 WINPR_ASSERT(remote_name);
320 file = make_synthetic_file(local_name, remote_name);
325 if (!ArrayList_Append(files, file))
327 free_synthetic_file(file);
331 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
337 if (!add_directory_contents_to_list(clipboard, local_name, remote_name, files))
344static const WCHAR* get_basename(
const WCHAR* name)
346 const WCHAR* c = name;
347 const WCHAR* last_name = name;
348 const WCHAR slash =
'/';
361static BOOL process_file_name(wClipboard* clipboard,
const WCHAR* local_name, wArrayList* files)
364 const WCHAR* base_name = NULL;
365 WCHAR* remote_name = NULL;
367 WINPR_ASSERT(clipboard);
368 WINPR_ASSERT(local_name);
376 base_name = get_basename(local_name);
377 remote_name = convert_local_name_component_to_remote(clipboard, base_name);
382 result = add_file_to_list(clipboard, local_name, remote_name, files);
387static BOOL process_uri(wClipboard* clipboard,
const char* uri,
size_t uri_len)
393 WINPR_ASSERT(clipboard);
395 name = parse_uri_to_local_file(uri, uri_len);
406 wname = ConvertUtf8ToWCharAlloc(name, NULL);
408 result = process_file_name(clipboard, wname, clipboard->localFiles);
417static BOOL process_uri_list(wClipboard* clipboard,
const char* data,
size_t length)
419 const char* cur = data;
420 const char* lim = data + length;
422 WINPR_ASSERT(clipboard);
425 WLog_VRB(TAG,
"processing URI list:\n%.*s", length, data);
426 ArrayList_Clear(clipboard->localFiles);
438 BOOL comment = (*cur ==
'#');
439 const char* start = cur;
440 const char* stop = cur;
442 for (; stop < lim; stop++)
446 if ((stop + 1 < lim) && (*(stop + 1) ==
'\n'))
463 if (strnlen(start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)) < 1)
471 if (!process_uri(clipboard, start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)))
478static BOOL convert_local_file_to_filedescriptor(
const struct synthetic_file* file,
481 size_t remote_len = 0;
484 WINPR_ASSERT(descriptor);
486 descriptor->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI;
488 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
490 descriptor->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
491 descriptor->nFileSizeLow = 0;
492 descriptor->nFileSizeHigh = 0;
496 descriptor->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
497 descriptor->nFileSizeLow = file->nFileSizeLow;
498 descriptor->nFileSizeHigh = file->nFileSizeHigh;
501 descriptor->ftLastWriteTime = file->ftLastWriteTime;
503 remote_len = _wcsnlen(file->remote_name, ARRAYSIZE(descriptor->cFileName));
505 if (remote_len >= ARRAYSIZE(descriptor->cFileName))
507 WLog_ERR(TAG,
"file name too long (%" PRIuz
" characters)", remote_len);
511 memcpy(descriptor->cFileName, file->remote_name, remote_len *
sizeof(WCHAR));
515static FILEDESCRIPTORW* convert_local_file_list_to_filedescriptors(wArrayList* files)
520 count = ArrayList_Count(files);
527 for (
size_t i = 0; i < count; i++)
529 const struct synthetic_file* file = ArrayList_GetItem(files, i);
531 if (!convert_local_file_to_filedescriptor(file, &descriptors[i]))
541static void* convert_any_uri_list_to_filedescriptors(wClipboard* clipboard,
542 WINPR_ATTR_UNUSED UINT32 formatId,
547 WINPR_ASSERT(clipboard);
550 descriptors = convert_local_file_list_to_filedescriptors(clipboard->localFiles);
555 *pSize = (UINT32)ArrayList_Count(clipboard->localFiles) *
sizeof(
FILEDESCRIPTORW);
556 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
560static void* convert_uri_list_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
561 const void* data, UINT32* pSize)
563 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_uri_list);
564 if (formatId != expected)
566 if (!process_uri_list(clipboard, (
const char*)data, *pSize))
568 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
571static BOOL process_files(wClipboard* clipboard,
const char* data, UINT32 pSize,
const char* prefix)
573 WINPR_ASSERT(prefix);
575 const size_t prefix_len = strlen(prefix);
577 WINPR_ASSERT(clipboard);
579 ArrayList_Clear(clipboard->localFiles);
581 if (!data || (pSize < prefix_len))
583 if (strncmp(data, prefix, prefix_len) != 0)
586 if (pSize < prefix_len)
588 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, prefix_len);
591 char* copy = strndup(data, pSize);
597 char* tok = strtok_s(copy,
"\n", &endptr);
600 const size_t tok_len = strnlen(tok, pSize);
601 if (!process_uri(clipboard, tok, tok_len))
605 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, tok_len);
606 tok = strtok_s(NULL,
"\n", &endptr);
617static BOOL process_gnome_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
619 return process_files(clipboard, data, pSize,
"copy\n");
622static BOOL process_mate_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
624 return process_files(clipboard, data, pSize,
"copy\n");
627static void* convert_gnome_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
628 const void* data, UINT32* pSize)
630 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_gnome_copied_files);
631 if (formatId != expected)
633 if (!process_gnome_copied_files(clipboard, (
const char*)data, *pSize))
635 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
638static void* convert_mate_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
639 const void* data, UINT32* pSize)
641 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_mate_copied_files);
642 if (formatId != expected)
645 if (!process_mate_copied_files(clipboard, (
const char*)data, *pSize))
648 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
651static size_t count_special_chars(
const WCHAR* str)
654 const WCHAR* start = str;
659 const WCHAR sharp =
'#';
660 const WCHAR questionmark =
'?';
661 const WCHAR star =
'*';
662 const WCHAR exclamationmark =
'!';
663 const WCHAR percent =
'%';
665 if ((*start == sharp) || (*start == questionmark) || (*start == star) ||
666 (*start == exclamationmark) || (*start == percent))
675static const char* stop_at_special_chars(
const char* str)
677 const char* start = str;
682 if (*start ==
'#' || *start ==
'?' || *start ==
'*' || *start ==
'!' || *start ==
'%')
692static void* convert_filedescriptors_to_file_list(wClipboard* clipboard, UINT32 formatId,
693 const void* data, UINT32* pSize,
694 const char* header,
const char* lineprefix,
695 const char* lineending, BOOL skip_last_lineending)
702 backslash.c[0] =
'\\';
703 backslash.c[1] =
'\0';
706 UINT32 nrDescriptors = 0;
710 size_t baseLength = 0;
712 size_t header_len = strlen(header);
713 size_t lineprefix_len = strlen(lineprefix);
714 size_t lineending_len = strlen(lineending);
715 size_t decoration_len = 0;
717 if (!clipboard || !data || !pSize)
720 if (*pSize <
sizeof(UINT32))
723 if (clipboard->delegate.basePath)
724 baseLength = strnlen(clipboard->delegate.basePath, MAX_PATH);
730 wStream* s = Stream_StaticConstInit(&sbuffer, data, *pSize);
731 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
734 Stream_Read_UINT32(s, nrDescriptors);
738 if ((count < 1) || (count != nrDescriptors))
741 descriptors = Stream_ConstPointer(s);
743 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
747 decoration_len = lineprefix_len + lineending_len + baseLength + 1;
751 for (
size_t x = 0; x < count; x++)
755 if (_wcschr(dsc->cFileName, backslash.w) == NULL)
757 alloc += ARRAYSIZE(dsc->cFileName) *
760 alloc += count_special_chars(dsc->cFileName) * 2;
761 alloc += decoration_len;
768 dst = calloc(alloc,
sizeof(
char));
773 (void)_snprintf(&dst[0], alloc,
"%s", header);
777 for (
size_t x = 0; x < count; x++)
781 if (_wcschr(dsc->cFileName, backslash.w) != NULL)
786 char curName[520] = { 0 };
787 const char* stop_at = NULL;
788 const char* previous_at = NULL;
790 if (ConvertWCharNToUtf8(dsc->cFileName, ARRAYSIZE(dsc->cFileName), curName,
791 ARRAYSIZE(curName)) < 0)
794 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s/", lineprefix, clipboard->delegate.basePath);
801 previous_at = curName;
802 while ((stop_at = stop_at_special_chars(previous_at)) != NULL)
804 const intptr_t diff = stop_at - previous_at;
807 char* tmp = strndup(previous_at, WINPR_ASSERTING_INT_CAST(
size_t, diff));
811 rc = _snprintf(&dst[pos], WINPR_ASSERTING_INT_CAST(
size_t, diff + 1),
"%s", tmp);
817 rc = _snprintf(&dst[pos], 4,
"%%%x", *stop_at);
822 previous_at = stop_at + 1;
825 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s", previous_at, lineending);
829 if ((rc < 0) || fail)
838 if (skip_last_lineending)
840 const size_t endlen = strlen(lineending);
843 const size_t len = strnlen(dst, alloc);
850 if (memcmp(&dst[len - endlen], lineending, endlen) == 0)
852 memset(&dst[len - endlen], 0, endlen);
858 alloc = strnlen(dst, alloc) + 1;
859 *pSize = (UINT32)alloc;
860 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
870static void* convert_filedescriptors_to_uri_list(wClipboard* clipboard, UINT32 formatId,
871 const void* data, UINT32* pSize)
873 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"",
"file://",
878static void* convert_filedescriptors_to_gnome_copied_files(wClipboard* clipboard, UINT32 formatId,
879 const void* data, UINT32* pSize)
881 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"copy\n",
882 "file://",
"\n", TRUE);
885static void* convert_filedescriptors_to_mate_copied_files(wClipboard* clipboard, UINT32 formatId,
886 const void* data, UINT32* pSize)
889 char* pDstData = convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
890 "copy\n",
"file://",
"\n", TRUE);
900 pDstData[*pSize - 1] =
'\0';
905static void array_free_synthetic_file(
void* the_file)
907 struct synthetic_file* file = the_file;
908 free_synthetic_file(file);
911static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard)
936 const UINT32 local_gnome_file_format_id =
937 ClipboardRegisterFormat(clipboard, mime_gnome_copied_files);
938 const UINT32 local_mate_file_format_id =
939 ClipboardRegisterFormat(clipboard, mime_mate_copied_files);
940 const UINT32 file_group_format_id =
941 ClipboardRegisterFormat(clipboard, mime_FileGroupDescriptorW);
942 const UINT32 local_file_format_id = ClipboardRegisterFormat(clipboard, mime_uri_list);
944 if (!file_group_format_id || !local_file_format_id || !local_gnome_file_format_id ||
945 !local_mate_file_format_id)
948 clipboard->localFiles = ArrayList_New(FALSE);
950 if (!clipboard->localFiles)
953 obj = ArrayList_Object(clipboard->localFiles);
954 obj->fnObjectFree = array_free_synthetic_file;
956 if (!ClipboardRegisterSynthesizer(clipboard, local_file_format_id, file_group_format_id,
957 convert_uri_list_to_filedescriptors))
958 goto error_free_local_files;
960 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_file_format_id,
961 convert_filedescriptors_to_uri_list))
962 goto error_free_local_files;
964 if (!ClipboardRegisterSynthesizer(clipboard, local_gnome_file_format_id, file_group_format_id,
965 convert_gnome_copied_files_to_filedescriptors))
966 goto error_free_local_files;
968 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_gnome_file_format_id,
969 convert_filedescriptors_to_gnome_copied_files))
970 goto error_free_local_files;
972 if (!ClipboardRegisterSynthesizer(clipboard, local_mate_file_format_id, file_group_format_id,
973 convert_mate_copied_files_to_filedescriptors))
974 goto error_free_local_files;
976 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_mate_file_format_id,
977 convert_filedescriptors_to_mate_copied_files))
978 goto error_free_local_files;
981error_free_local_files:
982 ArrayList_Free(clipboard->localFiles);
983 clipboard->localFiles = NULL;
988static int32_t file_get_size(
const struct synthetic_file* file, UINT64* size)
995 s = file->nFileSizeHigh;
997 s |= file->nFileSizeLow;
1002static UINT delegate_file_request_size(wClipboardDelegate* delegate,
1007 if (!delegate || !delegate->clipboard || !request)
1008 return ERROR_BAD_ARGUMENTS;
1010 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1011 return ERROR_INVALID_STATE;
1013 struct synthetic_file* file =
1014 ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1017 return ERROR_INDEX_ABSENT;
1019 const int32_t s = file_get_size(file, &size);
1022 error = delegate->ClipboardFileSizeFailure(delegate, request, (UINT)s);
1024 error = delegate->ClipboardFileSizeSuccess(delegate, request, size);
1027 WLog_WARN(TAG,
"failed to report file size result: 0x%08X", error);
1032UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force)
1034 if (!file || INVALID_HANDLE_VALUE == file->fd)
1040 file_get_size(file, &size);
1041 if ((file->offset < 0) || ((UINT64)file->offset >= size) || force)
1043 WLog_VRB(TAG,
"close file %d", file->fd);
1044 if (!CloseHandle(file->fd))
1046 WLog_WARN(TAG,
"failed to close fd %d: %" PRIu32, file->fd, GetLastError());
1049 file->fd = INVALID_HANDLE_VALUE;
1055static UINT file_get_range(
struct synthetic_file* file, UINT64 offset, UINT32 size,
1056 BYTE** actual_data, UINT32* actual_size)
1058 UINT error = NO_ERROR;
1063 WINPR_ASSERT(actual_data);
1064 WINPR_ASSERT(actual_size);
1066 if (INVALID_HANDLE_VALUE == file->fd)
1070 file->fd = CreateFileW(file->local_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1071 FILE_ATTRIBUTE_NORMAL, NULL);
1072 if (INVALID_HANDLE_VALUE == file->fd)
1074 error = GetLastError();
1075 WLog_ERR(TAG,
"failed to open file %s: 0x%08" PRIx32, file->local_name, error);
1079 if (!GetFileInformationByHandle(file->fd, &FileInfo))
1081 (void)CloseHandle(file->fd);
1082 file->fd = INVALID_HANDLE_VALUE;
1083 error = GetLastError();
1084 WLog_ERR(TAG,
"Get file [%s] information fail: 0x%08" PRIx32, file->local_name, error);
1089 file->nFileSizeHigh = FileInfo.nFileSizeHigh;
1090 file->nFileSizeLow = FileInfo.nFileSizeLow;
1109 if (offset > INT64_MAX)
1111 WLog_ERR(TAG,
"offset [%" PRIu64
"] > INT64_MAX", offset);
1116 if (file->offset != (INT64)offset)
1118 WLog_DBG(TAG,
"file %d force seeking to %" PRIu64
", current %" PRIu64, file->fd,
1119 offset, file->offset);
1121 dwHigh = offset >> 32;
1122 dwLow = offset & 0xFFFFFFFF;
1123 if (INVALID_SET_FILE_POINTER == SetFilePointer(file->fd,
1124 WINPR_ASSERTING_INT_CAST(LONG, dwLow),
1125 (PLONG)&dwHigh, FILE_BEGIN))
1127 error = GetLastError();
1132 BYTE* buffer = malloc(size);
1135 error = ERROR_NOT_ENOUGH_MEMORY;
1138 if (!ReadFile(file->fd, buffer, size, (LPDWORD)actual_size, NULL))
1141 error = GetLastError();
1145 *actual_data = buffer;
1146 file->offset += *actual_size;
1147 WLog_VRB(TAG,
"file %d actual read %" PRIu32
" bytes (offset %" PRIu64
")", file->fd,
1148 *actual_size, file->offset);
1151 synthetic_file_read_close(file, TRUE );
1155static UINT delegate_file_request_range(wClipboardDelegate* delegate,
1162 struct synthetic_file* file = NULL;
1164 if (!delegate || !delegate->clipboard || !request)
1165 return ERROR_BAD_ARGUMENTS;
1167 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1168 return ERROR_INVALID_STATE;
1170 file = ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1173 return ERROR_INDEX_ABSENT;
1175 offset = (((UINT64)request->nPositionHigh) << 32) | ((UINT64)request->nPositionLow);
1176 error = file_get_range(file, offset, request->cbRequested, &data, &size);
1179 error = delegate->ClipboardFileRangeFailure(delegate, request, error);
1181 error = delegate->ClipboardFileRangeSuccess(delegate, request, data, size);
1184 WLog_WARN(TAG,
"failed to report file range result: 0x%08X", error);
1190static UINT dummy_file_size_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1192 WINPR_ATTR_UNUSED UINT64 fileSize)
1194 return ERROR_NOT_SUPPORTED;
1197static UINT dummy_file_size_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1199 WINPR_ATTR_UNUSED UINT errorCode)
1201 return ERROR_NOT_SUPPORTED;
1204static UINT dummy_file_range_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1206 WINPR_ATTR_UNUSED
const BYTE* data,
1207 WINPR_ATTR_UNUSED UINT32 size)
1209 return ERROR_NOT_SUPPORTED;
1212static UINT dummy_file_range_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1214 WINPR_ATTR_UNUSED UINT errorCode)
1216 return ERROR_NOT_SUPPORTED;
1219static void setup_delegate(wClipboardDelegate* delegate)
1221 WINPR_ASSERT(delegate);
1223 delegate->ClientRequestFileSize = delegate_file_request_size;
1224 delegate->ClipboardFileSizeSuccess = dummy_file_size_success;
1225 delegate->ClipboardFileSizeFailure = dummy_file_size_failure;
1226 delegate->ClientRequestFileRange = delegate_file_request_range;
1227 delegate->ClipboardFileRangeSuccess = dummy_file_range_success;
1228 delegate->ClipboardFileRangeFailure = dummy_file_range_failure;
1229 delegate->IsFileNameComponentValid = ValidFileNameComponent;
1232BOOL ClipboardInitSyntheticFileSubsystem(wClipboard* clipboard)
1237 if (!register_file_formats_and_synthesizers(clipboard))
1240 setup_delegate(&clipboard->delegate);
This struct contains function pointer to initialize/free objects.