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 char name[MAX_PATH] = { 0 };
162 ConvertWCharToUtf8(local_name, name,
sizeof(name) - 1);
163 WLog_ERR(TAG,
"invalid file name component: %s", name);
173static WCHAR* concat_file_name(
const WCHAR* dir,
const WCHAR* file)
177 const WCHAR slash =
'/';
178 WCHAR* buffer = NULL;
183 len_dir = _wcslen(dir);
184 len_file = _wcslen(file);
185 buffer = calloc(len_dir + 1 + len_file + 2,
sizeof(WCHAR));
190 memcpy(buffer, dir, len_dir *
sizeof(WCHAR));
191 buffer[len_dir] = slash;
192 memcpy(buffer + len_dir + 1, file, len_file *
sizeof(WCHAR));
196static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
197 const WCHAR* remote_name, wArrayList* files);
199static BOOL add_directory_entry_to_list(wClipboard* clipboard,
const WCHAR* local_dir_name,
200 const WCHAR* remote_dir_name,
204 WCHAR* local_name = NULL;
205 WCHAR* remote_name = NULL;
206 WCHAR* remote_base_name = NULL;
208 WCHAR dotbuffer[6] = { 0 };
209 WCHAR dotdotbuffer[6] = { 0 };
210 const WCHAR* dot = InitializeConstWCharFromUtf8(
".", dotbuffer, ARRAYSIZE(dotbuffer));
211 const WCHAR* dotdot = InitializeConstWCharFromUtf8(
"..", dotdotbuffer, ARRAYSIZE(dotdotbuffer));
213 WINPR_ASSERT(clipboard);
214 WINPR_ASSERT(local_dir_name);
215 WINPR_ASSERT(remote_dir_name);
216 WINPR_ASSERT(pFileData);
221 if ((_wcscmp(pFileData->cFileName, dot) == 0) || (_wcscmp(pFileData->cFileName, dotdot) == 0))
224 remote_base_name = convert_local_name_component_to_remote(clipboard, pFileData->cFileName);
226 if (!remote_base_name)
229 local_name = concat_file_name(local_dir_name, pFileData->cFileName);
230 remote_name = concat_file_name(remote_dir_name, remote_base_name);
232 if (local_name && remote_name)
233 result = add_file_to_list(clipboard, local_name, remote_name, files);
235 free(remote_base_name);
241static BOOL do_add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
242 const WCHAR* remote_name, WCHAR* namebuf,
245 WINPR_ASSERT(clipboard);
246 WINPR_ASSERT(local_name);
247 WINPR_ASSERT(remote_name);
249 WINPR_ASSERT(namebuf);
252 HANDLE hFind = FindFirstFileW(namebuf, &FindData);
253 if (INVALID_HANDLE_VALUE == hFind)
255 WLog_ERR(TAG,
"FindFirstFile failed (%" PRIu32
")", GetLastError());
260 if (!add_directory_entry_to_list(clipboard, local_name, remote_name, &FindData, files))
266 BOOL bRet = FindNextFileW(hFind, &FindData);
270 if (ERROR_NO_MORE_FILES == GetLastError())
272 WLog_WARN(TAG,
"FindNextFile failed (%" PRIu32
")", GetLastError());
280static BOOL add_directory_contents_to_list(wClipboard* clipboard,
const WCHAR* local_name,
281 const WCHAR* remote_name, wArrayList* files)
289 const char buffer[6] = {
'/',
'\0',
'*',
'\0',
'\0',
'\0' };
291 const size_t wildcardLen = ARRAYSIZE(buffer) /
sizeof(WCHAR);
293 WINPR_ASSERT(clipboard);
294 WINPR_ASSERT(local_name);
295 WINPR_ASSERT(remote_name);
298 size_t len = _wcslen(local_name);
299 WCHAR* namebuf = calloc(len + wildcardLen,
sizeof(WCHAR));
303 _wcsncat(namebuf, local_name, len);
304 _wcsncat(namebuf, wildcard.w, wildcardLen);
306 result = do_add_directory_contents_to_list(clipboard, local_name, remote_name, namebuf, files);
312static BOOL add_file_to_list(wClipboard* clipboard,
const WCHAR* local_name,
313 const WCHAR* remote_name, wArrayList* files)
315 struct synthetic_file* file = NULL;
317 WINPR_ASSERT(clipboard);
318 WINPR_ASSERT(local_name);
319 WINPR_ASSERT(remote_name);
322 file = make_synthetic_file(local_name, remote_name);
327 if (!ArrayList_Append(files, file))
329 free_synthetic_file(file);
333 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
339 if (!add_directory_contents_to_list(clipboard, local_name, remote_name, files))
346static const WCHAR* get_basename(
const WCHAR* name)
348 const WCHAR* c = name;
349 const WCHAR* last_name = name;
350 const WCHAR slash =
'/';
363static BOOL process_file_name(wClipboard* clipboard,
const WCHAR* local_name, wArrayList* files)
366 const WCHAR* base_name = NULL;
367 WCHAR* remote_name = NULL;
369 WINPR_ASSERT(clipboard);
370 WINPR_ASSERT(local_name);
378 base_name = get_basename(local_name);
379 remote_name = convert_local_name_component_to_remote(clipboard, base_name);
384 result = add_file_to_list(clipboard, local_name, remote_name, files);
389static BOOL process_uri(wClipboard* clipboard,
const char* uri,
size_t uri_len)
395 WINPR_ASSERT(clipboard);
397 name = parse_uri_to_local_file(uri, uri_len);
408 wname = ConvertUtf8ToWCharAlloc(name, NULL);
410 result = process_file_name(clipboard, wname, clipboard->localFiles);
419static BOOL process_uri_list(wClipboard* clipboard,
const char* data,
size_t length)
421 const char* cur = data;
422 const char* lim = data + length;
424 WINPR_ASSERT(clipboard);
427 WLog_VRB(TAG,
"processing URI list:\n%.*s", WINPR_ASSERTING_INT_CAST(
int, length), data);
428 ArrayList_Clear(clipboard->localFiles);
440 BOOL comment = (*cur ==
'#');
441 const char* start = cur;
442 const char* stop = cur;
444 for (; stop < lim; stop++)
448 if ((stop + 1 < lim) && (*(stop + 1) ==
'\n'))
465 if (strnlen(start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)) < 1)
473 if (!process_uri(clipboard, start, WINPR_ASSERTING_INT_CAST(
size_t, stop - start)))
480static BOOL convert_local_file_to_filedescriptor(
const struct synthetic_file* file,
483 size_t remote_len = 0;
486 WINPR_ASSERT(descriptor);
488 descriptor->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_WRITESTIME | FD_PROGRESSUI;
490 if (file->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
492 descriptor->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
493 descriptor->nFileSizeLow = 0;
494 descriptor->nFileSizeHigh = 0;
498 descriptor->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
499 descriptor->nFileSizeLow = file->nFileSizeLow;
500 descriptor->nFileSizeHigh = file->nFileSizeHigh;
503 descriptor->ftLastWriteTime = file->ftLastWriteTime;
505 remote_len = _wcsnlen(file->remote_name, ARRAYSIZE(descriptor->cFileName));
507 if (remote_len >= ARRAYSIZE(descriptor->cFileName))
509 WLog_ERR(TAG,
"file name too long (%" PRIuz
" characters)", remote_len);
513 memcpy(descriptor->cFileName, file->remote_name, remote_len *
sizeof(WCHAR));
517static FILEDESCRIPTORW* convert_local_file_list_to_filedescriptors(wArrayList* files)
522 count = ArrayList_Count(files);
529 for (
size_t i = 0; i < count; i++)
531 const struct synthetic_file* file = ArrayList_GetItem(files, i);
533 if (!convert_local_file_to_filedescriptor(file, &descriptors[i]))
543static void* convert_any_uri_list_to_filedescriptors(wClipboard* clipboard,
544 WINPR_ATTR_UNUSED UINT32 formatId,
549 WINPR_ASSERT(clipboard);
552 descriptors = convert_local_file_list_to_filedescriptors(clipboard->localFiles);
557 *pSize = (UINT32)ArrayList_Count(clipboard->localFiles) *
sizeof(
FILEDESCRIPTORW);
558 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
562static void* convert_uri_list_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
563 const void* data, UINT32* pSize)
565 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_uri_list);
566 if (formatId != expected)
568 if (!process_uri_list(clipboard, (
const char*)data, *pSize))
570 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
573static BOOL process_files(wClipboard* clipboard,
const char* data, UINT32 pSize,
const char* prefix)
575 WINPR_ASSERT(prefix);
577 const size_t prefix_len = strlen(prefix);
579 WINPR_ASSERT(clipboard);
581 ArrayList_Clear(clipboard->localFiles);
583 if (!data || (pSize < prefix_len))
585 if (strncmp(data, prefix, prefix_len) != 0)
588 if (pSize < prefix_len)
590 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, prefix_len);
593 char* copy = strndup(data, pSize);
599 char* tok = strtok_s(copy,
"\n", &endptr);
602 const size_t tok_len = strnlen(tok, pSize);
603 if (!process_uri(clipboard, tok, tok_len))
607 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, tok_len);
608 tok = strtok_s(NULL,
"\n", &endptr);
619static BOOL process_gnome_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
621 return process_files(clipboard, data, pSize,
"copy\n");
624static BOOL process_mate_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
626 return process_files(clipboard, data, pSize,
"copy\n");
629static void* convert_gnome_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
630 const void* data, UINT32* pSize)
632 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_gnome_copied_files);
633 if (formatId != expected)
635 if (!process_gnome_copied_files(clipboard, (
const char*)data, *pSize))
637 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
640static void* convert_mate_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
641 const void* data, UINT32* pSize)
643 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_mate_copied_files);
644 if (formatId != expected)
647 if (!process_mate_copied_files(clipboard, (
const char*)data, *pSize))
650 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
653static size_t count_special_chars(
const WCHAR* str)
656 const WCHAR* start = str;
661 const WCHAR sharp =
'#';
662 const WCHAR questionmark =
'?';
663 const WCHAR star =
'*';
664 const WCHAR exclamationmark =
'!';
665 const WCHAR percent =
'%';
667 if ((*start == sharp) || (*start == questionmark) || (*start == star) ||
668 (*start == exclamationmark) || (*start == percent))
677static const char* stop_at_special_chars(
const char* str)
679 const char* start = str;
684 if (*start ==
'#' || *start ==
'?' || *start ==
'*' || *start ==
'!' || *start ==
'%')
694static void* convert_filedescriptors_to_file_list(wClipboard* clipboard, UINT32 formatId,
695 const void* data, UINT32* pSize,
696 const char* header,
const char* lineprefix,
697 const char* lineending, BOOL skip_last_lineending)
704 backslash.c[0] =
'\\';
705 backslash.c[1] =
'\0';
708 UINT32 nrDescriptors = 0;
712 size_t baseLength = 0;
714 size_t header_len = strlen(header);
715 size_t lineprefix_len = strlen(lineprefix);
716 size_t lineending_len = strlen(lineending);
717 size_t decoration_len = 0;
719 if (!clipboard || !data || !pSize)
722 if (*pSize <
sizeof(UINT32))
725 if (clipboard->delegate.basePath)
726 baseLength = strnlen(clipboard->delegate.basePath, MAX_PATH);
732 wStream* s = Stream_StaticConstInit(&sbuffer, data, *pSize);
733 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
736 Stream_Read_UINT32(s, nrDescriptors);
740 if ((count < 1) || (count != nrDescriptors))
743 descriptors = Stream_ConstPointer(s);
745 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
749 decoration_len = lineprefix_len + lineending_len + baseLength + 1;
753 for (
size_t x = 0; x < count; x++)
757 if (_wcschr(dsc->cFileName, backslash.w) == NULL)
759 alloc += ARRAYSIZE(dsc->cFileName) *
762 alloc += count_special_chars(dsc->cFileName) * 2;
763 alloc += decoration_len;
770 dst = calloc(alloc,
sizeof(
char));
775 (void)_snprintf(&dst[0], alloc,
"%s", header);
779 for (
size_t x = 0; x < count; x++)
783 if (_wcschr(dsc->cFileName, backslash.w) != NULL)
788 char curName[520] = { 0 };
789 const char* stop_at = NULL;
790 const char* previous_at = NULL;
792 if (ConvertWCharNToUtf8(dsc->cFileName, ARRAYSIZE(dsc->cFileName), curName,
793 ARRAYSIZE(curName)) < 0)
796 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s/", lineprefix, clipboard->delegate.basePath);
803 previous_at = curName;
804 while ((stop_at = stop_at_special_chars(previous_at)) != NULL)
806 const intptr_t diff = stop_at - previous_at;
809 char* tmp = strndup(previous_at, WINPR_ASSERTING_INT_CAST(
size_t, diff));
813 rc = _snprintf(&dst[pos], WINPR_ASSERTING_INT_CAST(
size_t, diff + 1),
"%s", tmp);
819 rc = _snprintf(&dst[pos], 4,
"%%%x", *stop_at);
824 previous_at = stop_at + 1;
827 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s", previous_at, lineending);
831 if ((rc < 0) || fail)
840 if (skip_last_lineending)
842 const size_t endlen = strlen(lineending);
845 const size_t len = strnlen(dst, alloc);
852 if (memcmp(&dst[len - endlen], lineending, endlen) == 0)
854 memset(&dst[len - endlen], 0, endlen);
860 alloc = strnlen(dst, alloc) + 1;
861 *pSize = (UINT32)alloc;
862 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
872static void* convert_filedescriptors_to_uri_list(wClipboard* clipboard, UINT32 formatId,
873 const void* data, UINT32* pSize)
875 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"",
"file://",
880static void* convert_filedescriptors_to_gnome_copied_files(wClipboard* clipboard, UINT32 formatId,
881 const void* data, UINT32* pSize)
883 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"copy\n",
884 "file://",
"\n", TRUE);
887static void* convert_filedescriptors_to_mate_copied_files(wClipboard* clipboard, UINT32 formatId,
888 const void* data, UINT32* pSize)
891 char* pDstData = convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
892 "copy\n",
"file://",
"\n", TRUE);
902 pDstData[*pSize - 1] =
'\0';
907static void array_free_synthetic_file(
void* the_file)
909 struct synthetic_file* file = the_file;
910 free_synthetic_file(file);
913static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard)
938 const UINT32 local_gnome_file_format_id =
939 ClipboardRegisterFormat(clipboard, mime_gnome_copied_files);
940 const UINT32 local_mate_file_format_id =
941 ClipboardRegisterFormat(clipboard, mime_mate_copied_files);
942 const UINT32 file_group_format_id =
943 ClipboardRegisterFormat(clipboard, mime_FileGroupDescriptorW);
944 const UINT32 local_file_format_id = ClipboardRegisterFormat(clipboard, mime_uri_list);
946 if (!file_group_format_id || !local_file_format_id || !local_gnome_file_format_id ||
947 !local_mate_file_format_id)
950 clipboard->localFiles = ArrayList_New(FALSE);
952 if (!clipboard->localFiles)
955 obj = ArrayList_Object(clipboard->localFiles);
956 obj->fnObjectFree = array_free_synthetic_file;
958 if (!ClipboardRegisterSynthesizer(clipboard, local_file_format_id, file_group_format_id,
959 convert_uri_list_to_filedescriptors))
960 goto error_free_local_files;
962 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_file_format_id,
963 convert_filedescriptors_to_uri_list))
964 goto error_free_local_files;
966 if (!ClipboardRegisterSynthesizer(clipboard, local_gnome_file_format_id, file_group_format_id,
967 convert_gnome_copied_files_to_filedescriptors))
968 goto error_free_local_files;
970 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_gnome_file_format_id,
971 convert_filedescriptors_to_gnome_copied_files))
972 goto error_free_local_files;
974 if (!ClipboardRegisterSynthesizer(clipboard, local_mate_file_format_id, file_group_format_id,
975 convert_mate_copied_files_to_filedescriptors))
976 goto error_free_local_files;
978 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_mate_file_format_id,
979 convert_filedescriptors_to_mate_copied_files))
980 goto error_free_local_files;
983error_free_local_files:
984 ArrayList_Free(clipboard->localFiles);
985 clipboard->localFiles = NULL;
990static int32_t file_get_size(
const struct synthetic_file* file, UINT64* size)
997 s = file->nFileSizeHigh;
999 s |= file->nFileSizeLow;
1004static UINT delegate_file_request_size(wClipboardDelegate* delegate,
1009 if (!delegate || !delegate->clipboard || !request)
1010 return ERROR_BAD_ARGUMENTS;
1012 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1013 return ERROR_INVALID_STATE;
1015 struct synthetic_file* file =
1016 ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1019 return ERROR_INDEX_ABSENT;
1021 const int32_t s = file_get_size(file, &size);
1024 error = delegate->ClipboardFileSizeFailure(delegate, request, (UINT)s);
1026 error = delegate->ClipboardFileSizeSuccess(delegate, request, size);
1029 WLog_WARN(TAG,
"failed to report file size result: 0x%08X", error);
1034UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force)
1036 if (!file || INVALID_HANDLE_VALUE == file->fd)
1042 file_get_size(file, &size);
1043 if ((file->offset < 0) || ((UINT64)file->offset >= size) || force)
1045 WLog_VRB(TAG,
"close file %p", file->fd);
1046 if (!CloseHandle(file->fd))
1048 WLog_WARN(TAG,
"failed to close fd %p: %" PRIu32, file->fd, GetLastError());
1051 file->fd = INVALID_HANDLE_VALUE;
1057static UINT file_get_range(
struct synthetic_file* file, UINT64 offset, UINT32 size,
1058 BYTE** actual_data, UINT32* actual_size)
1060 UINT error = NO_ERROR;
1065 WINPR_ASSERT(actual_data);
1066 WINPR_ASSERT(actual_size);
1068 if (INVALID_HANDLE_VALUE == file->fd)
1072 file->fd = CreateFileW(file->local_name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1073 FILE_ATTRIBUTE_NORMAL, NULL);
1074 if (INVALID_HANDLE_VALUE == file->fd)
1076 char name[MAX_PATH] = { 0 };
1077 ConvertWCharToUtf8(file->local_name, name,
sizeof(name) - 1);
1078 error = GetLastError();
1079 WLog_ERR(TAG,
"failed to open file %s: 0x%08" PRIx32, name, error);
1083 if (!GetFileInformationByHandle(file->fd, &FileInfo))
1085 char name[MAX_PATH] = { 0 };
1086 ConvertWCharToUtf8(file->local_name, name,
sizeof(name) - 1);
1087 (void)CloseHandle(file->fd);
1088 file->fd = INVALID_HANDLE_VALUE;
1089 error = GetLastError();
1090 WLog_ERR(TAG,
"Get file [%s] information fail: 0x%08" PRIx32, name, error);
1095 file->nFileSizeHigh = FileInfo.nFileSizeHigh;
1096 file->nFileSizeLow = FileInfo.nFileSizeLow;
1115 if (offset > INT64_MAX)
1117 WLog_ERR(TAG,
"offset [%" PRIu64
"] > INT64_MAX", offset);
1122 if (file->offset != (INT64)offset)
1124 WLog_DBG(TAG,
"file %p force seeking to %" PRIu64
", current %" PRId64, file->fd,
1125 offset, file->offset);
1127 dwHigh = offset >> 32;
1128 dwLow = offset & 0xFFFFFFFF;
1129 if (INVALID_SET_FILE_POINTER == SetFilePointer(file->fd,
1130 WINPR_ASSERTING_INT_CAST(LONG, dwLow),
1131 (PLONG)&dwHigh, FILE_BEGIN))
1133 error = GetLastError();
1138 BYTE* buffer = malloc(size);
1141 error = ERROR_NOT_ENOUGH_MEMORY;
1144 if (!ReadFile(file->fd, buffer, size, (LPDWORD)actual_size, NULL))
1147 error = GetLastError();
1151 *actual_data = buffer;
1152 file->offset += *actual_size;
1153 WLog_VRB(TAG,
"file %p actual read %" PRIu32
" bytes (offset %" PRId64
")", file->fd,
1154 *actual_size, file->offset);
1157 synthetic_file_read_close(file, TRUE );
1161static UINT delegate_file_request_range(wClipboardDelegate* delegate,
1168 struct synthetic_file* file = NULL;
1170 if (!delegate || !delegate->clipboard || !request)
1171 return ERROR_BAD_ARGUMENTS;
1173 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1174 return ERROR_INVALID_STATE;
1176 file = ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1179 return ERROR_INDEX_ABSENT;
1181 offset = (((UINT64)request->nPositionHigh) << 32) | ((UINT64)request->nPositionLow);
1182 error = file_get_range(file, offset, request->cbRequested, &data, &size);
1185 error = delegate->ClipboardFileRangeFailure(delegate, request, error);
1187 error = delegate->ClipboardFileRangeSuccess(delegate, request, data, size);
1190 WLog_WARN(TAG,
"failed to report file range result: 0x%08X", error);
1196static UINT dummy_file_size_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1198 WINPR_ATTR_UNUSED UINT64 fileSize)
1200 return ERROR_NOT_SUPPORTED;
1203static UINT dummy_file_size_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1205 WINPR_ATTR_UNUSED UINT errorCode)
1207 return ERROR_NOT_SUPPORTED;
1210static UINT dummy_file_range_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1212 WINPR_ATTR_UNUSED
const BYTE* data,
1213 WINPR_ATTR_UNUSED UINT32 size)
1215 return ERROR_NOT_SUPPORTED;
1218static UINT dummy_file_range_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1220 WINPR_ATTR_UNUSED UINT errorCode)
1222 return ERROR_NOT_SUPPORTED;
1225static void setup_delegate(wClipboardDelegate* delegate)
1227 WINPR_ASSERT(delegate);
1229 delegate->ClientRequestFileSize = delegate_file_request_size;
1230 delegate->ClipboardFileSizeSuccess = dummy_file_size_success;
1231 delegate->ClipboardFileSizeFailure = dummy_file_size_failure;
1232 delegate->ClientRequestFileRange = delegate_file_request_range;
1233 delegate->ClipboardFileRangeSuccess = dummy_file_range_success;
1234 delegate->ClipboardFileRangeFailure = dummy_file_range_failure;
1235 delegate->IsFileNameComponentValid = ValidFileNameComponent;
1238BOOL ClipboardInitSyntheticFileSubsystem(wClipboard* clipboard)
1243 if (!register_file_formats_and_synthesizers(clipboard))
1246 setup_delegate(&clipboard->delegate);
This struct contains function pointer to initialize/free objects.