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 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_uri_list);
567 if (formatId != expected)
569 if (!process_uri_list(clipboard, (
const char*)data, *pSize))
571 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
574static BOOL process_files(wClipboard* clipboard,
const char* data, UINT32 pSize,
const char* prefix)
576 WINPR_ASSERT(prefix);
578 const size_t prefix_len = strlen(prefix);
580 WINPR_ASSERT(clipboard);
582 ArrayList_Clear(clipboard->localFiles);
584 if (!data || (pSize < prefix_len))
586 if (strncmp(data, prefix, prefix_len) != 0)
589 if (pSize < prefix_len)
591 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, prefix_len);
594 char* copy = strndup(data, pSize);
599 char* endptr =
nullptr;
600 char* tok = strtok_s(copy,
"\n", &endptr);
603 const size_t tok_len = strnlen(tok, pSize);
604 if (!process_uri(clipboard, tok, tok_len))
608 pSize -= WINPR_ASSERTING_INT_CAST(uint32_t, tok_len);
609 tok = strtok_s(
nullptr,
"\n", &endptr);
620static BOOL process_gnome_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
622 return process_files(clipboard, data, pSize,
"copy\n");
625static BOOL process_mate_copied_files(wClipboard* clipboard,
const char* data, UINT32 pSize)
627 return process_files(clipboard, data, pSize,
"copy\n");
630static void* convert_gnome_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
631 const void* data, UINT32* pSize)
633 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_gnome_copied_files);
634 if (formatId != expected)
636 if (!process_gnome_copied_files(clipboard, (
const char*)data, *pSize))
638 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
641static void* convert_mate_copied_files_to_filedescriptors(wClipboard* clipboard, UINT32 formatId,
642 const void* data, UINT32* pSize)
644 const UINT32 expected = ClipboardGetFormatId(clipboard, mime_mate_copied_files);
645 if (formatId != expected)
648 if (!process_mate_copied_files(clipboard, (
const char*)data, *pSize))
651 return convert_any_uri_list_to_filedescriptors(clipboard, formatId, pSize);
654static size_t count_special_chars(
const WCHAR* str)
657 const WCHAR* start = str;
662 const WCHAR sharp =
'#';
663 const WCHAR questionmark =
'?';
664 const WCHAR star =
'*';
665 const WCHAR exclamationmark =
'!';
666 const WCHAR percent =
'%';
668 if ((*start == sharp) || (*start == questionmark) || (*start == star) ||
669 (*start == exclamationmark) || (*start == percent))
678static const char* stop_at_special_chars(
const char* str)
680 const char* start = str;
685 if (*start ==
'#' || *start ==
'?' || *start ==
'*' || *start ==
'!' || *start ==
'%')
695static void* convert_filedescriptors_to_file_list(wClipboard* clipboard, UINT32 formatId,
696 const void* data, UINT32* pSize,
697 const char* header,
const char* lineprefix,
698 const char* lineending, BOOL skip_last_lineending)
705 backslash.c[0] =
'\\';
706 backslash.c[1] =
'\0';
709 UINT32 nrDescriptors = 0;
713 size_t baseLength = 0;
715 size_t header_len = strlen(header);
716 size_t lineprefix_len = strlen(lineprefix);
717 size_t lineending_len = strlen(lineending);
718 size_t decoration_len = 0;
720 if (!clipboard || !data || !pSize)
723 if (*pSize <
sizeof(UINT32))
726 if (clipboard->delegate.basePath)
727 baseLength = strnlen(clipboard->delegate.basePath, MAX_PATH);
732 wStream sbuffer = WINPR_C_ARRAY_INIT;
733 wStream* s = Stream_StaticConstInit(&sbuffer, data, *pSize);
734 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
737 Stream_Read_UINT32(s, nrDescriptors);
741 if ((count < 1) || (count != nrDescriptors))
744 descriptors = Stream_ConstPointer(s);
746 if (formatId != ClipboardGetFormatId(clipboard, mime_FileGroupDescriptorW))
750 decoration_len = lineprefix_len + lineending_len + baseLength + 1;
754 for (
size_t x = 0; x < count; x++)
758 if (_wcschr(dsc->cFileName, backslash.w) ==
nullptr)
760 alloc += ARRAYSIZE(dsc->cFileName) *
763 alloc += count_special_chars(dsc->cFileName) *
sizeof(WCHAR);
764 alloc += decoration_len;
771 dst = calloc(alloc,
sizeof(
char));
776 (void)_snprintf(&dst[0], alloc,
"%s", header);
780 for (
size_t x = 0; x < count; x++)
784 if (_wcschr(dsc->cFileName, backslash.w) !=
nullptr)
789 char curName[520] = WINPR_C_ARRAY_INIT;
790 const char* stop_at =
nullptr;
791 const char* previous_at =
nullptr;
793 if (ConvertWCharNToUtf8(dsc->cFileName, ARRAYSIZE(dsc->cFileName), curName,
794 ARRAYSIZE(curName)) < 0)
797 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s/", lineprefix, clipboard->delegate.basePath);
804 previous_at = curName;
805 while ((stop_at = stop_at_special_chars(previous_at)) !=
nullptr)
807 const intptr_t diff = stop_at - previous_at;
810 char* tmp = strndup(previous_at, WINPR_ASSERTING_INT_CAST(
size_t, diff));
814 rc = _snprintf(&dst[pos], WINPR_ASSERTING_INT_CAST(
size_t, diff + 1),
"%s", tmp);
820 rc = _snprintf(&dst[pos], 4,
"%%%x", *stop_at);
825 previous_at = stop_at + 1;
828 rc = _snprintf(&dst[pos], alloc - pos,
"%s%s", previous_at, lineending);
832 if ((rc < 0) || fail)
841 if (skip_last_lineending)
843 const size_t endlen = strlen(lineending);
846 const size_t len = strnlen(dst, alloc);
853 if (memcmp(&dst[len - endlen], lineending, endlen) == 0)
855 memset(&dst[len - endlen], 0, endlen);
861 alloc = strnlen(dst, alloc) + 1;
862 *pSize = (UINT32)alloc;
863 clipboard->fileListSequenceNumber = clipboard->sequenceNumber;
873static void* convert_filedescriptors_to_uri_list(wClipboard* clipboard, UINT32 formatId,
874 const void* data, UINT32* pSize)
876 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"",
"file://",
881static void* convert_filedescriptors_to_gnome_copied_files(wClipboard* clipboard, UINT32 formatId,
882 const void* data, UINT32* pSize)
884 return convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
"copy\n",
885 "file://",
"\n", TRUE);
888static void* convert_filedescriptors_to_mate_copied_files(wClipboard* clipboard, UINT32 formatId,
889 const void* data, UINT32* pSize)
892 char* pDstData = convert_filedescriptors_to_file_list(clipboard, formatId, data, pSize,
893 "copy\n",
"file://",
"\n", TRUE);
903 pDstData[*pSize - 1] =
'\0';
908static void array_free_synthetic_file(
void* the_file)
910 struct synthetic_file* file = the_file;
911 free_synthetic_file(file);
914static BOOL register_file_formats_and_synthesizers(wClipboard* clipboard)
939 const UINT32 local_gnome_file_format_id =
940 ClipboardRegisterFormat(clipboard, mime_gnome_copied_files);
941 const UINT32 local_mate_file_format_id =
942 ClipboardRegisterFormat(clipboard, mime_mate_copied_files);
943 const UINT32 file_group_format_id =
944 ClipboardRegisterFormat(clipboard, mime_FileGroupDescriptorW);
945 const UINT32 local_file_format_id = ClipboardRegisterFormat(clipboard, mime_uri_list);
947 if (!file_group_format_id || !local_file_format_id || !local_gnome_file_format_id ||
948 !local_mate_file_format_id)
951 clipboard->localFiles = ArrayList_New(FALSE);
953 if (!clipboard->localFiles)
956 obj = ArrayList_Object(clipboard->localFiles);
959 if (!ClipboardRegisterSynthesizer(clipboard, local_file_format_id, file_group_format_id,
960 convert_uri_list_to_filedescriptors))
961 goto error_free_local_files;
963 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_file_format_id,
964 convert_filedescriptors_to_uri_list))
965 goto error_free_local_files;
967 if (!ClipboardRegisterSynthesizer(clipboard, local_gnome_file_format_id, file_group_format_id,
968 convert_gnome_copied_files_to_filedescriptors))
969 goto error_free_local_files;
971 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_gnome_file_format_id,
972 convert_filedescriptors_to_gnome_copied_files))
973 goto error_free_local_files;
975 if (!ClipboardRegisterSynthesizer(clipboard, local_mate_file_format_id, file_group_format_id,
976 convert_mate_copied_files_to_filedescriptors))
977 goto error_free_local_files;
979 if (!ClipboardRegisterSynthesizer(clipboard, file_group_format_id, local_mate_file_format_id,
980 convert_filedescriptors_to_mate_copied_files))
981 goto error_free_local_files;
984error_free_local_files:
985 ArrayList_Free(clipboard->localFiles);
986 clipboard->localFiles =
nullptr;
991static int32_t file_get_size(
const struct synthetic_file* file, UINT64* size)
998 s = file->nFileSizeHigh;
1000 s |= file->nFileSizeLow;
1005static UINT delegate_file_request_size(wClipboardDelegate* delegate,
1010 if (!delegate || !delegate->clipboard || !request)
1011 return ERROR_BAD_ARGUMENTS;
1013 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1014 return ERROR_INVALID_STATE;
1016 struct synthetic_file* file =
1017 ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1020 return ERROR_INDEX_ABSENT;
1022 const int32_t s = file_get_size(file, &size);
1025 error = delegate->ClipboardFileSizeFailure(delegate, request, (UINT)s);
1027 error = delegate->ClipboardFileSizeSuccess(delegate, request, size);
1030 WLog_WARN(TAG,
"failed to report file size result: 0x%08X", error);
1035UINT synthetic_file_read_close(
struct synthetic_file* file, BOOL force)
1037 if (!file || INVALID_HANDLE_VALUE == file->fd)
1043 file_get_size(file, &size);
1044 if ((file->offset < 0) || ((UINT64)file->offset >= size) || force)
1046 WLog_VRB(TAG,
"close file %p", file->fd);
1047 if (!CloseHandle(file->fd))
1049 WLog_WARN(TAG,
"failed to close fd %p: %" PRIu32, file->fd, GetLastError());
1052 file->fd = INVALID_HANDLE_VALUE;
1058static UINT file_get_range(
struct synthetic_file* file, UINT64 offset, UINT32 size,
1059 BYTE** actual_data, UINT32* actual_size)
1061 UINT error = NO_ERROR;
1066 WINPR_ASSERT(actual_data);
1067 WINPR_ASSERT(actual_size);
1069 if (INVALID_HANDLE_VALUE == file->fd)
1073 file->fd = CreateFileW(file->local_name, GENERIC_READ, 0,
nullptr, OPEN_EXISTING,
1074 FILE_ATTRIBUTE_NORMAL,
nullptr);
1075 if (INVALID_HANDLE_VALUE == file->fd)
1077 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
1078 ConvertWCharToUtf8(file->local_name, name,
sizeof(name) - 1);
1079 error = GetLastError();
1080 WLog_ERR(TAG,
"failed to open file %s: 0x%08" PRIx32, name, error);
1084 if (!GetFileInformationByHandle(file->fd, &FileInfo))
1086 char name[MAX_PATH] = WINPR_C_ARRAY_INIT;
1087 ConvertWCharToUtf8(file->local_name, name,
sizeof(name) - 1);
1088 (void)CloseHandle(file->fd);
1089 file->fd = INVALID_HANDLE_VALUE;
1090 error = GetLastError();
1091 WLog_ERR(TAG,
"Get file [%s] information fail: 0x%08" PRIx32, name, error);
1096 file->nFileSizeHigh = FileInfo.nFileSizeHigh;
1097 file->nFileSizeLow = FileInfo.nFileSizeLow;
1116 if (offset > INT64_MAX)
1118 WLog_ERR(TAG,
"offset [%" PRIu64
"] > INT64_MAX", offset);
1123 if (file->offset != (INT64)offset)
1125 WLog_DBG(TAG,
"file %p force seeking to %" PRIu64
", current %" PRId64, file->fd,
1126 offset, file->offset);
1128 dwHigh = offset >> 32;
1129 dwLow = offset & 0xFFFFFFFF;
1130 if (INVALID_SET_FILE_POINTER == SetFilePointer(file->fd,
1131 WINPR_ASSERTING_INT_CAST(LONG, dwLow),
1132 (PLONG)&dwHigh, FILE_BEGIN))
1134 error = GetLastError();
1139 BYTE* buffer = malloc(size);
1142 error = ERROR_NOT_ENOUGH_MEMORY;
1145 if (!ReadFile(file->fd, buffer, size, (LPDWORD)actual_size,
nullptr))
1148 error = GetLastError();
1152 *actual_data = buffer;
1153 file->offset += *actual_size;
1154 WLog_VRB(TAG,
"file %p actual read %" PRIu32
" bytes (offset %" PRId64
")", file->fd,
1155 *actual_size, file->offset);
1158 synthetic_file_read_close(file, TRUE );
1162static UINT delegate_file_request_range(wClipboardDelegate* delegate,
1166 BYTE* data =
nullptr;
1169 struct synthetic_file* file =
nullptr;
1171 if (!delegate || !delegate->clipboard || !request)
1172 return ERROR_BAD_ARGUMENTS;
1174 if (delegate->clipboard->sequenceNumber != delegate->clipboard->fileListSequenceNumber)
1175 return ERROR_INVALID_STATE;
1177 file = ArrayList_GetItem(delegate->clipboard->localFiles, request->listIndex);
1180 return ERROR_INDEX_ABSENT;
1182 offset = (((UINT64)request->nPositionHigh) << 32) | ((UINT64)request->nPositionLow);
1183 error = file_get_range(file, offset, request->cbRequested, &data, &size);
1186 error = delegate->ClipboardFileRangeFailure(delegate, request, error);
1188 error = delegate->ClipboardFileRangeSuccess(delegate, request, data, size);
1191 WLog_WARN(TAG,
"failed to report file range result: 0x%08X", error);
1197static UINT dummy_file_size_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1199 WINPR_ATTR_UNUSED UINT64 fileSize)
1201 return ERROR_NOT_SUPPORTED;
1204static UINT dummy_file_size_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1206 WINPR_ATTR_UNUSED UINT errorCode)
1208 return ERROR_NOT_SUPPORTED;
1211static UINT dummy_file_range_success(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1213 WINPR_ATTR_UNUSED
const BYTE* data,
1214 WINPR_ATTR_UNUSED UINT32 size)
1216 return ERROR_NOT_SUPPORTED;
1219static UINT dummy_file_range_failure(WINPR_ATTR_UNUSED wClipboardDelegate* delegate,
1221 WINPR_ATTR_UNUSED UINT errorCode)
1223 return ERROR_NOT_SUPPORTED;
1226static void setup_delegate(wClipboardDelegate* delegate)
1228 WINPR_ASSERT(delegate);
1230 delegate->ClientRequestFileSize = delegate_file_request_size;
1231 delegate->ClipboardFileSizeSuccess = dummy_file_size_success;
1232 delegate->ClipboardFileSizeFailure = dummy_file_size_failure;
1233 delegate->ClientRequestFileRange = delegate_file_request_range;
1234 delegate->ClipboardFileRangeSuccess = dummy_file_range_success;
1235 delegate->ClipboardFileRangeFailure = dummy_file_range_failure;
1236 delegate->IsFileNameComponentValid = ValidFileNameComponent;
1239BOOL ClipboardInitSyntheticFileSubsystem(wClipboard* clipboard)
1244 if (!register_file_formats_and_synthesizers(clipboard))
1247 setup_delegate(&clipboard->delegate);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree