20#include <freerdp/config.h>
27#include <winpr/synch.h>
28#include <winpr/print.h>
29#include <winpr/stream.h>
30#include <winpr/cmdline.h>
31#include <winpr/collections.h>
33#include <freerdp/addin.h>
34#include <freerdp/client/channels.h>
35#include <freerdp/client/geometry.h>
36#include <freerdp/channels/log.h>
38#define TAG CHANNELS_TAG("geometry.client")
40#include "geometry_main.h"
45 GeometryClientContext* context;
48static UINT32 mappedGeometryHash(
const void* v)
50 const UINT64* g = (
const UINT64*)v;
51 return (UINT32)((*g >> 32) + (*g & 0xffffffff));
54static BOOL mappedGeometryKeyCompare(
const void* v1,
const void* v2)
56 const UINT64* g1 = (
const UINT64*)v1;
57 const UINT64* g2 = (
const UINT64*)v2;
68 WINPR_ASSERT(rgndata);
72 WLog_Print(logger, WLOG_ERROR,
"invalid RGNDATA");
73 return ERROR_INVALID_DATA;
76 const UINT32 dwSize = Stream_Get_UINT32(s);
80 WLog_Print(logger, WLOG_ERROR,
"invalid RGNDATA dwSize");
81 return ERROR_INVALID_DATA;
84 const UINT32 iType = Stream_Get_UINT32(s);
86 if (iType != RDH_RECTANGLE)
88 WLog_Print(logger, WLOG_ERROR,
"iType %" PRIu32
" for RGNDATA is not supported", iType);
89 return ERROR_UNSUPPORTED_TYPE;
92 rgndata->nRectCount = Stream_Get_UINT32(s);
93 Stream_Seek_UINT32(s);
95 const INT32 x = Stream_Get_INT32(s);
96 const INT32 y = Stream_Get_INT32(s);
97 const INT32 right = Stream_Get_INT32(s);
98 const INT32 bottom = Stream_Get_INT32(s);
99 if ((abs(x) > INT16_MAX) || (abs(y) > INT16_MAX))
100 return ERROR_INVALID_DATA;
101 const INT32 w = right - x;
102 const INT32 h = bottom - y;
103 if ((abs(w) > INT16_MAX) || (abs(h) > INT16_MAX))
104 return ERROR_INVALID_DATA;
105 rgndata->boundingRect.x = (INT16)x;
106 rgndata->boundingRect.y = (INT16)y;
107 rgndata->boundingRect.width = (INT16)w;
108 rgndata->boundingRect.height = (INT16)h;
112 if (len / (4 * 4) < rgndata->nRectCount)
114 WLog_Print(logger, WLOG_ERROR,
"not enough data for region rectangles");
115 return ERROR_INVALID_DATA;
118 if (rgndata->nRectCount)
120 RDP_RECT* tmp = realloc(rgndata->rects, rgndata->nRectCount *
sizeof(
RDP_RECT));
124 WLog_Print(logger, WLOG_ERROR,
"unable to allocate memory for %" PRIu32
" RECTs",
125 rgndata->nRectCount);
126 return CHANNEL_RC_NO_MEMORY;
128 rgndata->rects = tmp;
130 for (UINT32 i = 0; i < rgndata->nRectCount; i++)
132 RDP_RECT* rect = &rgndata->rects[i];
134 if (!Stream_CheckAndLogRequiredLengthWLog(logger, s, 16))
135 return CHANNEL_RC_NULL_DATA;
137 const INT32 x = Stream_Get_INT32(s);
138 const INT32 y = Stream_Get_INT32(s);
139 const INT32 right = Stream_Get_INT32(s);
140 const INT32 bottom = Stream_Get_INT32(s);
141 if ((abs(x) > INT16_MAX) || (abs(y) > INT16_MAX))
142 return ERROR_INVALID_DATA;
144 const INT32 w = right - x;
145 const INT32 h = bottom - y;
146 if ((abs(w) > INT16_MAX) || (abs(h) > INT16_MAX))
147 return ERROR_INVALID_DATA;
151 rect->width = (INT16)w;
152 rect->height = (INT16)h;
156 return CHANNEL_RC_OK;
166 UINT ret = CHANNEL_RC_OK;
168 WINPR_ASSERT(callback);
169 GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)callback->plugin;
170 WINPR_ASSERT(geometry);
172 wLog* logger = geometry->base.log;
173 GeometryClientContext* context = (GeometryClientContext*)geometry->base.iface.pInterface;
174 WINPR_ASSERT(context);
176 if (!Stream_CheckAndLogRequiredLengthWLog(logger, s, 4))
177 return ERROR_INVALID_DATA;
179 const UINT32 length = Stream_Get_UINT32(s);
181 if (!Stream_CheckAndLogRequiredLengthWLog(logger, s, (length - 4)))
183 WLog_Print(logger, WLOG_ERROR,
"invalid packet length");
184 return ERROR_INVALID_DATA;
187 if (!Stream_CheckAndLogRequiredLengthWLog(logger, s, 20))
188 return ERROR_INVALID_DATA;
190 context->remoteVersion = Stream_Get_UINT32(s);
191 const UINT64
id = Stream_Get_UINT64(s);
192 const UINT32 updateType = Stream_Get_UINT32(s);
193 Stream_Seek_UINT32(s);
195 MAPPED_GEOMETRY* mappedGeometry = HashTable_GetItemValue(context->geometries, &
id);
197 if (updateType == GEOMETRY_CLEAR)
201 WLog_Print(logger, WLOG_ERROR,
202 "geometry 0x%" PRIx64
" not found here, ignoring clear command",
id);
203 return CHANNEL_RC_OK;
206 WLog_Print(logger, WLOG_DEBUG,
"clearing geometry 0x%" PRIx64
"",
id);
208 if (mappedGeometry->MappedGeometryClear &&
209 !mappedGeometry->MappedGeometryClear(mappedGeometry))
210 return ERROR_INTERNAL_ERROR;
212 if (!HashTable_Remove(context->geometries, &
id))
213 WLog_Print(logger, WLOG_ERROR,
"geometry not removed from geometries");
215 else if (updateType == GEOMETRY_UPDATE)
222 WLog_Print(logger, WLOG_DEBUG,
"creating geometry 0x%" PRIx64
"",
id);
223 mappedGeometry = calloc(1,
sizeof(MAPPED_GEOMETRY));
225 return CHANNEL_RC_NO_MEMORY;
227 mappedGeometry->refCounter = 1;
228 mappedGeometry->mappingId = id;
230 if (!HashTable_Insert(context->geometries, &(mappedGeometry->mappingId),
233 WLog_Print(logger, WLOG_ERROR,
234 "unable to register geometry 0x%" PRIx64
" in the table",
id);
235 free(mappedGeometry);
236 return CHANNEL_RC_NO_MEMORY;
241 WLog_Print(logger, WLOG_DEBUG,
"updating geometry 0x%" PRIx64
"",
id);
244 if (!Stream_CheckAndLogRequiredLengthWLog(logger, s, 48))
247 return ERROR_INVALID_DATA;
250 mappedGeometry->topLevelId = Stream_Get_UINT64(s);
252 mappedGeometry->left = Stream_Get_INT32(s);
253 mappedGeometry->top = Stream_Get_INT32(s);
254 mappedGeometry->right = Stream_Get_INT32(s);
255 mappedGeometry->bottom = Stream_Get_INT32(s);
257 mappedGeometry->topLevelLeft = Stream_Get_INT32(s);
258 mappedGeometry->topLevelTop = Stream_Get_INT32(s);
259 mappedGeometry->topLevelRight = Stream_Get_INT32(s);
260 mappedGeometry->topLevelBottom = Stream_Get_INT32(s);
262 const UINT32 geometryType = Stream_Get_UINT32(s);
263 if (geometryType != 0x02)
264 WLog_Print(logger, WLOG_DEBUG,
"geometryType should be set to 0x02 and is 0x%" PRIx32,
267 const UINT32 cbGeometryBuffer = Stream_Get_UINT32(s);
268 if (!Stream_CheckAndLogRequiredLengthWLog(logger, s, cbGeometryBuffer))
271 return ERROR_INVALID_DATA;
274 if (cbGeometryBuffer > 0)
276 ret = geometry_read_RGNDATA(logger, s, cbGeometryBuffer, &mappedGeometry->geometry);
277 if (ret != CHANNEL_RC_OK)
282 freerdp_rgndata_reset(&mappedGeometry->geometry);
287 if (context->MappedGeometryAdded &&
288 !context->MappedGeometryAdded(context, mappedGeometry))
290 WLog_Print(logger, WLOG_ERROR,
"geometry added callback failed");
291 ret = ERROR_INTERNAL_ERROR;
296 if (mappedGeometry->MappedGeometryUpdate &&
297 !mappedGeometry->MappedGeometryUpdate(mappedGeometry))
299 WLog_Print(logger, WLOG_ERROR,
"geometry update callback failed");
300 ret = ERROR_INTERNAL_ERROR;
306 WLog_Print(logger, WLOG_ERROR,
"unknown updateType=%" PRIu32
"", updateType);
318static UINT geometry_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
321 return geometry_recv_pdu(callback, data);
329static UINT geometry_on_close(IWTSVirtualChannelCallback* pChannelCallback)
331 free(pChannelCallback);
332 return CHANNEL_RC_OK;
335static void mappedGeometryUnref_void(
void* arg)
337 MAPPED_GEOMETRY* g = (MAPPED_GEOMETRY*)arg;
338 mappedGeometryUnref(g);
345static const IWTSVirtualChannelCallback geometry_callbacks = { geometry_on_data_received,
347 geometry_on_close, NULL };
350 rdpSettings* settings)
352 GeometryClientContext* context = NULL;
353 GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)base;
356 WINPR_UNUSED(settings);
358 context = (GeometryClientContext*)calloc(1,
sizeof(GeometryClientContext));
361 WLog_Print(base->log, WLOG_ERROR,
"calloc failed!");
362 return CHANNEL_RC_NO_MEMORY;
365 context->geometries = HashTable_New(FALSE);
366 if (!context->geometries)
368 WLog_Print(base->log, WLOG_ERROR,
"unable to allocate geometries");
370 return CHANNEL_RC_NO_MEMORY;
373 HashTable_SetHashFunction(context->geometries, mappedGeometryHash);
375 wObject* obj = HashTable_KeyObject(context->geometries);
376 obj->fnObjectEquals = mappedGeometryKeyCompare;
379 wObject* obj = HashTable_ValueObject(context->geometries);
380 obj->fnObjectFree = mappedGeometryUnref_void;
382 context->handle = (
void*)geometry;
384 geometry->context = context;
385 geometry->base.iface.pInterface = (
void*)context;
387 return CHANNEL_RC_OK;
392 GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)base;
394 if (geometry->context)
395 HashTable_Free(geometry->context->geometries);
396 free(geometry->context);
404FREERDP_ENTRY_POINT(UINT VCAPITYPE geometry_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
406 return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, GEOMETRY_DVC_CHANNEL_NAME,
408 &geometry_callbacks, init_plugin_cb, terminate_plugin_cb);
This struct contains function pointer to initialize/free objects.