22#include <winpr/stream.h>
23#include <freerdp/utils/cliprdr_utils.h>
24#include <freerdp/channels/cliprdr.h>
26#include <freerdp/log.h>
27#define TAG FREERDP_TAG("utils." CLIPRDR_SVC_CHANNEL_NAME)
29#define CLIPRDR_FILEDESCRIPTOR_SIZE (4 + 32 + 4 + 16 + 8 + 8 + 520)
30#define CLIPRDR_MAX_FILE_SIZE (2U * 1024 * 1024 * 1024)
32static UINT64 filetime_to_uint64(
FILETIME value)
35 converted |= (UINT32)value.dwHighDateTime;
37 converted |= (UINT32)value.dwLowDateTime;
41static FILETIME uint64_to_filetime(UINT64 value)
44 converted.dwLowDateTime = (UINT32)(value >> 0);
45 converted.dwHighDateTime = (UINT32)(value >> 32);
61UINT cliprdr_parse_file_list(
const BYTE* format_data, UINT32 format_data_length,
64 UINT result = NO_ERROR;
66 wStream sbuffer = WINPR_C_ARRAY_INIT;
68 if (!format_data || !file_descriptor_array || !file_descriptor_count)
69 return ERROR_BAD_ARGUMENTS;
71 wStream* s = Stream_StaticConstInit(&sbuffer, format_data, format_data_length);
73 return ERROR_NOT_ENOUGH_MEMORY;
75 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
77 result = ERROR_INCORRECT_SIZE;
81 Stream_Read_UINT32(s, count);
83 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, count, CLIPRDR_FILEDESCRIPTOR_SIZE))
85 result = ERROR_INCORRECT_SIZE;
89 *file_descriptor_count = count;
91 if (!*file_descriptor_array)
93 result = ERROR_NOT_ENOUGH_MEMORY;
97 for (UINT32 i = 0; i < count; i++)
101 if (!cliprdr_read_filedescriptor(s, file))
105 if (Stream_GetRemainingLength(s) > 0)
106 WLog_WARN(TAG,
"packed file list has %" PRIuz
" excess bytes",
107 Stream_GetRemainingLength(s));
114static BOOL contains_dotdot(
const WCHAR* path,
size_t path_length)
119 size_t tstlen = path_length;
120 const WCHAR* tst = path;
123 tst = winpr_wcsnchr(tst, tstlen,
'.');
126 const size_t diff = WINPR_ASSERTING_INT_CAST(
size_t, tst - path);
127 tstlen = _wcsnlen(tst, path_length - diff);
134 if ((tst == path) || (*(tst - 1) == L
'/') || (*(tst - 1) == L
'\\'))
136 if (tst + 2 < path + path_length)
138 if ((tst[2] ==
'/') || (tst[2] ==
'\\') || (tst[2] ==
'\0'))
153 WINPR_ASSERT(descriptor);
155 if (!Stream_CheckAndLogRequiredLength(TAG, s,
sizeof(
FILEDESCRIPTORW)))
158 Stream_Read_UINT32(s, descriptor->dwFlags);
159 Stream_Read_UINT32(s, descriptor->clsid.Data1);
160 Stream_Read_UINT16(s, descriptor->clsid.Data2);
161 Stream_Read_UINT16(s, descriptor->clsid.Data3);
162 Stream_Read(s, &descriptor->clsid.Data4,
sizeof(descriptor->clsid.Data4));
163 Stream_Read_INT32(s, descriptor->sizel.cx);
164 Stream_Read_INT32(s, descriptor->sizel.cy);
165 Stream_Read_INT32(s, descriptor->pointl.x);
166 Stream_Read_INT32(s, descriptor->pointl.y);
167 Stream_Read_UINT32(s, descriptor->dwFileAttributes);
168 Stream_Read_UINT64(s, tmp);
169 descriptor->ftCreationTime = uint64_to_filetime(tmp);
170 Stream_Read_UINT64(s, tmp);
171 descriptor->ftLastAccessTime = uint64_to_filetime(tmp);
172 Stream_Read_UINT64(s, tmp);
173 descriptor->ftLastWriteTime = uint64_to_filetime(tmp);
174 Stream_Read_UINT32(s, descriptor->nFileSizeHigh);
175 Stream_Read_UINT32(s, descriptor->nFileSizeLow);
176 if (!Stream_Read_UTF16_String(s, descriptor->cFileName,
177 ARRAYSIZE(descriptor->cFileName)))
179 if (contains_dotdot(descriptor->cFileName, ARRAYSIZE(descriptor->cFileName)))
186 WINPR_ASSERT(descriptor);
191 Stream_Write_UINT32(s, descriptor->dwFlags);
193 Stream_Write_UINT32(s, descriptor->clsid.Data1);
194 Stream_Write_UINT16(s, descriptor->clsid.Data2);
195 Stream_Write_UINT16(s, descriptor->clsid.Data3);
196 Stream_Write(s, &descriptor->clsid.Data4,
sizeof(descriptor->clsid.Data4));
197 Stream_Write_INT32(s, descriptor->sizel.cx);
198 Stream_Write_INT32(s, descriptor->sizel.cy);
199 Stream_Write_INT32(s, descriptor->pointl.x);
200 Stream_Write_INT32(s, descriptor->pointl.y);
201 Stream_Write_UINT32(s, descriptor->dwFileAttributes);
202 Stream_Write_UINT64(s, filetime_to_uint64(descriptor->ftCreationTime));
203 Stream_Write_UINT64(s, filetime_to_uint64(descriptor->ftLastAccessTime));
205 s, filetime_to_uint64(descriptor->ftLastWriteTime));
206 Stream_Write_UINT32(s, descriptor->nFileSizeHigh);
207 Stream_Write_UINT32(s, descriptor->nFileSizeLow);
208 return Stream_Write_UTF16_String(s, descriptor->cFileName,
209 ARRAYSIZE(descriptor->cFileName));
224UINT cliprdr_serialize_file_list(
const FILEDESCRIPTORW* file_descriptor_array,
225 UINT32 file_descriptor_count, BYTE** format_data,
226 UINT32* format_data_length)
228 return cliprdr_serialize_file_list_ex(CB_STREAM_FILECLIP_ENABLED, file_descriptor_array,
229 file_descriptor_count, format_data, format_data_length);
232UINT cliprdr_serialize_file_list_ex(UINT32 flags,
const FILEDESCRIPTORW* file_descriptor_array,
233 UINT32 file_descriptor_count, BYTE** format_data,
234 UINT32* format_data_length)
236 UINT result = NO_ERROR;
240 if (!file_descriptor_array || !format_data || !format_data_length)
241 return ERROR_BAD_ARGUMENTS;
243 if ((flags & CB_STREAM_FILECLIP_ENABLED) == 0)
245 WLog_WARN(TAG,
"No file clipboard support annouonced!");
246 return ERROR_BAD_ARGUMENTS;
249 s = Stream_New(
nullptr, 4 + file_descriptor_count * CLIPRDR_FILEDESCRIPTOR_SIZE);
251 return ERROR_NOT_ENOUGH_MEMORY;
253 Stream_Write_UINT32(s, file_descriptor_count);
255 for (UINT32 i = 0; i < file_descriptor_count; i++)
266 if ((flags & CB_HUGE_FILE_SUPPORT_ENABLED) == 0)
268 if ((file->nFileSizeHigh > 0) || (file->nFileSizeLow >= CLIPRDR_MAX_FILE_SIZE))
270 WLog_ERR(TAG,
"cliprdr does not support files over 2 GB");
271 result = ERROR_FILE_TOO_LARGE;
276 if (!cliprdr_write_filedescriptor(s, file))
280 Stream_SealLength(s);
282 *format_data = Stream_Buffer(s);
283 Stream_GetLength(s, len);
284 if (len > UINT32_MAX)
287 *format_data_length = (UINT32)len;
289 Stream_Free(s, FALSE);
294 Stream_Free(s, TRUE);