VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/clipboard-common.cpp@ 86649

Last change on this file since 86649 was 86247, checked in by vboxsync, 4 years ago

SharedClipboard/win: Build fix (strict/win) and some cleanup.

  • Property eol-style set to native
  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 31.9 KB
Line 
1/* $Id: clipboard-common.cpp 86247 2020-09-23 16:44:40Z vboxsync $ */
2/** @file
3 * Shared Clipboard: Some helper function for converting between the various eol.
4 */
5
6/*
7 * Includes contributions from François Revol
8 *
9 * Copyright (C) 2006-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
21
22#include <iprt/alloc.h>
23#include <iprt/assert.h>
24#include <iprt/semaphore.h>
25#include <iprt/path.h>
26#include <iprt/rand.h>
27#include <iprt/utf16.h>
28
29#include <iprt/formats/bmp.h>
30
31#include <iprt/errcore.h>
32#include <VBox/log.h>
33#include <VBox/GuestHost/clipboard-helper.h>
34#include <VBox/HostServices/VBoxClipboardSvc.h>
35
36
37/*********************************************************************************************************************************
38* Prototypes *
39*********************************************************************************************************************************/
40DECLINLINE(PSHCLEVENT) shclEventGet(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent);
41
42
43/*********************************************************************************************************************************
44* Implementation *
45*********************************************************************************************************************************/
46
47/**
48 * Allocates a new event payload.
49 *
50 * @returns VBox status code.
51 * @param uID Payload ID to set for this payload. Useful for consequtive payloads.
52 * @param pvData Data block to associate to this payload.
53 * @param cbData Size (in bytes) of data block to associate.
54 * @param ppPayload Where to store the allocated event payload on success.
55 */
56int ShClPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData,
57 PSHCLEVENTPAYLOAD *ppPayload)
58{
59 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
60 AssertReturn(cbData > 0, VERR_INVALID_PARAMETER);
61
62 PSHCLEVENTPAYLOAD pPayload = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
63 if (pPayload)
64 {
65 pPayload->pvData = RTMemDup(pvData, cbData);
66 if (pPayload->pvData)
67 {
68 pPayload->cbData = cbData;
69 pPayload->uID = uID;
70
71 *ppPayload = pPayload;
72 return VINF_SUCCESS;
73 }
74
75 RTMemFree(pPayload);
76 }
77 return VERR_NO_MEMORY;
78}
79
80/**
81 * Frees an event payload.
82 *
83 * @returns VBox status code.
84 * @param pPayload Event payload to free.
85 */
86void ShClPayloadFree(PSHCLEVENTPAYLOAD pPayload)
87{
88 if (!pPayload)
89 return;
90
91 if (pPayload->pvData)
92 {
93 Assert(pPayload->cbData);
94 RTMemFree(pPayload->pvData);
95 pPayload->pvData = NULL;
96 }
97
98 pPayload->cbData = 0;
99 pPayload->uID = UINT32_MAX;
100
101 RTMemFree(pPayload);
102}
103
104/**
105 * Destroys an event, but doesn't free the memory.
106 *
107 * @param pEvent Event to destroy.
108 */
109static void shClEventTerm(PSHCLEVENT pEvent)
110{
111 if (!pEvent)
112 return;
113
114 AssertMsgReturnVoid(pEvent->cRefs == 0, ("Event %RU32 still has %RU32 references\n",
115 pEvent->idEvent, pEvent->cRefs));
116
117 LogFlowFunc(("Event %RU32\n", pEvent->idEvent));
118
119 if (pEvent->hEvtMulSem != NIL_RTSEMEVENT)
120 {
121 RTSemEventMultiDestroy(pEvent->hEvtMulSem);
122 pEvent->hEvtMulSem = NIL_RTSEMEVENT;
123 }
124
125 ShClPayloadFree(pEvent->pPayload);
126
127 pEvent->idEvent = 0;
128}
129
130/**
131 * Creates a new event source.
132 *
133 * @returns VBox status code.
134 * @param pSource Event source to create.
135 * @param uID ID to use for event source.
136 */
137int ShClEventSourceCreate(PSHCLEVENTSOURCE pSource, SHCLEVENTSOURCEID uID)
138{
139 LogFlowFunc(("pSource=%p, uID=%RU16\n", pSource, uID));
140 AssertPtrReturn(pSource, VERR_INVALID_POINTER);
141
142 RTListInit(&pSource->lstEvents);
143
144 pSource->uID = uID;
145 /* Choose a random event ID starting point. */
146 pSource->idNextEvent = RTRandU32Ex(1, VBOX_SHCL_MAX_EVENTS - 1);
147
148 LogFlowFuncLeaveRC(VINF_SUCCESS);
149 return VINF_SUCCESS;
150}
151
152/**
153 * Destroys an event source.
154 *
155 * @param pSource Event source to destroy.
156 */
157void ShClEventSourceDestroy(PSHCLEVENTSOURCE pSource)
158{
159 if (!pSource)
160 return;
161
162 LogFlowFunc(("ID=%RU32\n", pSource->uID));
163
164 ShClEventSourceReset(pSource);
165
166 pSource->uID = UINT16_MAX;
167 pSource->idNextEvent = UINT32_MAX;
168}
169
170/**
171 * Resets an event source.
172 *
173 * @param pSource Event source to reset.
174 */
175void ShClEventSourceReset(PSHCLEVENTSOURCE pSource)
176{
177 LogFlowFunc(("ID=%RU32\n", pSource->uID));
178
179 PSHCLEVENT pEvIt;
180 PSHCLEVENT pEvItNext;
181 RTListForEachSafe(&pSource->lstEvents, pEvIt, pEvItNext, SHCLEVENT, Node)
182 {
183 RTListNodeRemove(&pEvIt->Node);
184
185 shClEventTerm(pEvIt);
186
187 RTMemFree(pEvIt);
188 pEvIt = NULL;
189 }
190}
191
192/**
193 * Generates a new event ID for a specific event source and registers it.
194 *
195 * @returns New event ID generated, or NIL_SHCLEVENTID on error.
196 * @param pSource Event source to generate event for.
197 */
198SHCLEVENTID ShClEventIdGenerateAndRegister(PSHCLEVENTSOURCE pSource)
199{
200 AssertPtrReturn(pSource, NIL_SHCLEVENTID);
201
202 /*
203 * Allocate an event.
204 */
205 PSHCLEVENT pEvent = (PSHCLEVENT)RTMemAllocZ(sizeof(SHCLEVENT));
206 AssertReturn(pEvent, NIL_SHCLEVENTID);
207 int rc = RTSemEventMultiCreate(&pEvent->hEvtMulSem);
208 AssertRCReturnStmt(rc, RTMemFree(pEvent), NIL_SHCLEVENTID);
209
210 /*
211 * Allocate an unique event ID.
212 */
213 for (uint32_t cTries = 0;; cTries++)
214 {
215 SHCLEVENTID idEvent = ++pSource->idNextEvent;
216 if (idEvent < VBOX_SHCL_MAX_EVENTS)
217 { /* likely */ }
218 else
219 pSource->idNextEvent = idEvent = 1; /* zero == error, remember! */
220
221 if (shclEventGet(pSource, idEvent) == NULL)
222 {
223 pEvent->idEvent = idEvent;
224 RTListAppend(&pSource->lstEvents, &pEvent->Node);
225
226 LogFlowFunc(("uSource=%RU16: New event: %#x\n", pSource->uID, idEvent));
227 return idEvent;
228 }
229
230 AssertBreak(cTries < 4096);
231 }
232
233 AssertMsgFailed(("Unable to register a new event ID for event source %RU16\n", pSource->uID));
234
235 RTMemFree(pEvent);
236 return NIL_SHCLEVENTID;
237}
238
239/**
240 * Returns a specific event of a event source. Inlined version.
241 *
242 * @returns Pointer to event if found, or NULL if not found.
243 * @param pSource Event source to get event from.
244 * @param uID Event ID to get.
245 */
246DECLINLINE(PSHCLEVENT) shclEventGet(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent)
247{
248 PSHCLEVENT pEvent;
249 RTListForEach(&pSource->lstEvents, pEvent, SHCLEVENT, Node)
250 {
251 if (pEvent->idEvent == idEvent)
252 return pEvent;
253 }
254
255 return NULL;
256}
257
258/**
259 * Returns a specific event of a event source.
260 *
261 * @returns Pointer to event if found, or NULL if not found.
262 * @param pSource Event source to get event from.
263 * @param uID Event ID to get.
264 */
265PSHCLEVENT ShClEventGet(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent)
266{
267 return shclEventGet(pSource, idEvent);
268}
269
270/**
271 * Returns the last (newest) event ID which has been registered for an event source.
272 *
273 * @returns Last registered event ID, or 0 if not found.
274 * @param pSource Event source to get last registered event from.
275 */
276SHCLEVENTID ShClEventGetLast(PSHCLEVENTSOURCE pSource)
277{
278 AssertPtrReturn(pSource, 0);
279 PSHCLEVENT pEvent = RTListGetLast(&pSource->lstEvents, SHCLEVENT, Node);
280 if (pEvent)
281 return pEvent->idEvent;
282
283 return 0;
284}
285
286/**
287 * Returns the current reference count for a specific event.
288 *
289 * @returns Reference count.
290 * @param pSource Event source the specific event is part of.
291 * @param idEvent Event ID to return reference count for.
292 */
293uint32_t ShClEventGetRefs(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent)
294{
295 PSHCLEVENT pEvent = shclEventGet(pSource, idEvent);
296 if (pEvent)
297 return pEvent->cRefs;
298
299 AssertMsgFailed(("No event with %RU32\n", idEvent));
300 return 0;
301}
302
303/**
304 * Detaches a payload from an event, internal version.
305 *
306 * @returns Pointer to the detached payload. Can be NULL if the payload has no payload.
307 * @param pEvent Event to detach payload for.
308 */
309static PSHCLEVENTPAYLOAD shclEventPayloadDetachInternal(PSHCLEVENT pEvent)
310{
311#ifdef VBOX_STRICT
312 AssertPtrReturn(pEvent, NULL);
313#endif
314
315 PSHCLEVENTPAYLOAD pPayload = pEvent->pPayload;
316
317 pEvent->pPayload = NULL;
318
319 return pPayload;
320}
321
322/**
323 * Unregisters an event.
324 *
325 * @returns VBox status code.
326 * @param pSource Event source to unregister event for.
327 * @param uID Event ID to unregister.
328 */
329int ShClEventUnregister(PSHCLEVENTSOURCE pSource, SHCLEVENTID uID)
330{
331 AssertPtrReturn(pSource, VERR_INVALID_POINTER);
332
333 int rc;
334
335 LogFlowFunc(("uSource=%RU16, uEvent=%RU32\n", pSource->uID, uID));
336
337 PSHCLEVENT pEvent = shclEventGet(pSource, uID);
338 if (pEvent)
339 {
340 LogFlowFunc(("Event %RU32\n", pEvent->idEvent));
341
342 RTListNodeRemove(&pEvent->Node);
343
344 shClEventTerm(pEvent);
345
346 RTMemFree(pEvent);
347 pEvent = NULL;
348
349 rc = VINF_SUCCESS;
350 }
351 else
352 rc = VERR_NOT_FOUND;
353
354 LogFlowFuncLeaveRC(rc);
355 return rc;
356}
357
358/**
359 * Waits for an event to get signalled.
360 *
361 * @returns VBox status code.
362 * @param pSource Event source that contains the event to wait for.
363 * @param uID Event ID to wait for.
364 * @param uTimeoutMs Timeout (in ms) to wait.
365 * @param ppPayload Where to store the (allocated) event payload on success. Needs to be free'd with
366 * SharedClipboardPayloadFree(). Optional.
367 */
368int ShClEventWait(PSHCLEVENTSOURCE pSource, SHCLEVENTID uID, RTMSINTERVAL uTimeoutMs,
369 PSHCLEVENTPAYLOAD* ppPayload)
370{
371 AssertPtrReturn(pSource, VERR_INVALID_POINTER);
372 /** ppPayload is optional. */
373
374 LogFlowFuncEnter();
375
376 int rc;
377
378 PSHCLEVENT pEvent = shclEventGet(pSource, uID);
379 if (pEvent)
380 {
381 rc = RTSemEventMultiWait(pEvent->hEvtMulSem, uTimeoutMs);
382 if (RT_SUCCESS(rc))
383 {
384 if (ppPayload)
385 {
386 /* Make sure to detach payload here, as the caller now owns the data. */
387 *ppPayload = shclEventPayloadDetachInternal(pEvent);
388 }
389 }
390 }
391 else
392 rc = VERR_NOT_FOUND;
393
394 LogFlowFuncLeaveRC(rc);
395 return rc;
396}
397
398/**
399 * Retains an event by increasing its reference count.
400 *
401 * @returns New reference count, or UINT32_MAX if failed.
402 * @param pSource Event source of event to retain.
403 * @param idEvent ID of event to retain.
404 */
405uint32_t ShClEventRetain(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent)
406{
407 PSHCLEVENT pEvent = shclEventGet(pSource, idEvent);
408 if (!pEvent)
409 {
410 AssertFailed();
411 return UINT32_MAX;
412 }
413
414 AssertReturn(pEvent->cRefs < 64, UINT32_MAX); /* Sanity. Yeah, not atomic. */
415
416 return ASMAtomicIncU32(&pEvent->cRefs);
417}
418
419/**
420 * Releases an event by decreasing its reference count.
421 *
422 * @returns New reference count, or UINT32_MAX if failed.
423 * @param pSource Event source of event to release.
424 * @param idEvent ID of event to release.
425 */
426uint32_t ShClEventRelease(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent)
427{
428 PSHCLEVENT pEvent = shclEventGet(pSource, idEvent);
429 if (!pEvent)
430 {
431 AssertFailed();
432 return UINT32_MAX;
433 }
434
435 AssertReturn(pEvent->cRefs, UINT32_MAX); /* Sanity. Yeah, not atomic. */
436
437 return ASMAtomicDecU32(&pEvent->cRefs);
438}
439
440/**
441 * Signals an event.
442 *
443 * @returns VBox status code.
444 * @param pSource Event source of event to signal.
445 * @param uID Event ID to signal.
446 * @param pPayload Event payload to associate. Takes ownership. Optional.
447 *
448 * @note Caller must enter crit sect protecting the event source!
449 */
450int ShClEventSignal(PSHCLEVENTSOURCE pSource, SHCLEVENTID uID,
451 PSHCLEVENTPAYLOAD pPayload)
452{
453 AssertPtrReturn(pSource, VERR_INVALID_POINTER);
454
455 int rc;
456
457 LogFlowFunc(("uSource=%RU16, uEvent=%RU32\n", pSource->uID, uID));
458
459 PSHCLEVENT pEvent = shclEventGet(pSource, uID);
460 if (pEvent)
461 {
462 Assert(pEvent->pPayload == NULL);
463
464 pEvent->pPayload = pPayload;
465
466 rc = RTSemEventMultiSignal(pEvent->hEvtMulSem);
467 }
468 else
469 rc = VERR_NOT_FOUND;
470
471 LogFlowFuncLeaveRC(rc);
472 return rc;
473}
474
475int ShClUtf16LenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen)
476{
477 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
478 AssertPtrReturn(pchLen, VERR_INVALID_POINTER);
479
480 size_t chLen = 0;
481 int rc = RTUtf16CalcUtf8LenEx(pcwszSrc, cwcSrc, &chLen);
482 if (RT_SUCCESS(rc))
483 *pchLen = chLen;
484 return rc;
485}
486
487int ShClConvUtf16CRLFToUtf8LF(PCRTUTF16 pcwszSrc, size_t cwcSrc,
488 char *pszBuf, size_t cbBuf, size_t *pcbLen)
489{
490 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
491 AssertReturn (cwcSrc, VERR_INVALID_PARAMETER);
492 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
493 AssertPtrReturn(pcbLen, VERR_INVALID_POINTER);
494
495 int rc;
496
497 PRTUTF16 pwszTmp = NULL;
498 size_t cchTmp = 0;
499
500 size_t cbLen = 0;
501
502 /* How long will the converted text be? */
503 rc = ShClUtf16CRLFLenUtf8(pcwszSrc, cwcSrc, &cchTmp);
504 if (RT_SUCCESS(rc))
505 {
506 cchTmp++; /* Add space for terminator. */
507
508 pwszTmp = (PRTUTF16)RTMemAlloc(cchTmp * sizeof(RTUTF16));
509 if (pwszTmp)
510 {
511 rc = ShClConvUtf16CRLFToLF(pcwszSrc, cwcSrc, pwszTmp, cchTmp);
512 if (RT_SUCCESS(rc))
513 rc = RTUtf16ToUtf8Ex(pwszTmp + 1, cchTmp - 1, &pszBuf, cbBuf, &cbLen);
514
515 RTMemFree(reinterpret_cast<void *>(pwszTmp));
516 }
517 else
518 rc = VERR_NO_MEMORY;
519 }
520
521 if (RT_SUCCESS(rc))
522 {
523 *pcbLen = cbLen;
524 }
525
526 LogFlowFuncLeaveRC(rc);
527 return rc;
528}
529
530int ShClConvUtf16LFToCRLFA(PCRTUTF16 pcwszSrc, size_t cwcSrc,
531 PRTUTF16 *ppwszDst, size_t *pcwDst)
532{
533 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
534 AssertPtrReturn(ppwszDst, VERR_INVALID_POINTER);
535 AssertPtrReturn(pcwDst, VERR_INVALID_POINTER);
536
537 PRTUTF16 pwszDst = NULL;
538 size_t cchDst;
539
540 int rc = ShClUtf16LFLenUtf8(pcwszSrc, cwcSrc, &cchDst);
541 if (RT_SUCCESS(rc))
542 {
543 pwszDst = (PRTUTF16)RTMemAlloc((cchDst + 1 /* Leave space for terminator */) * sizeof(RTUTF16));
544 if (pwszDst)
545 {
546 rc = ShClConvUtf16LFToCRLF(pcwszSrc, cwcSrc, pwszDst, cchDst + 1 /* Include terminator */);
547 }
548 else
549 rc = VERR_NO_MEMORY;
550 }
551
552 if (RT_SUCCESS(rc))
553 {
554 *ppwszDst = pwszDst;
555 *pcwDst = cchDst;
556 }
557 else
558 RTMemFree(pwszDst);
559
560 LogFlowFuncLeaveRC(rc);
561 return rc;
562}
563
564int ShClConvUtf8LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc,
565 PRTUTF16 *ppwszDst, size_t *pcwDst)
566{
567 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
568 AssertReturn(cbSrc, VERR_INVALID_PARAMETER);
569 AssertPtrReturn(ppwszDst, VERR_INVALID_POINTER);
570 AssertPtrReturn(pcwDst, VERR_INVALID_POINTER);
571
572 /* Intermediate conversion to UTF-16. */
573 size_t cwcTmp;
574 PRTUTF16 pwcTmp = NULL;
575 int rc = RTStrToUtf16Ex(pcszSrc, cbSrc, &pwcTmp, 0, &cwcTmp);
576 if (RT_SUCCESS(rc))
577 {
578 rc = ShClConvUtf16LFToCRLFA(pwcTmp, cwcTmp, ppwszDst, pcwDst);
579 RTUtf16Free(pwcTmp);
580 }
581
582 LogFlowFuncLeaveRC(rc);
583 return rc;
584}
585
586int ShClConvLatin1LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc,
587 PRTUTF16 *ppwszDst, size_t *pcwDst)
588{
589 AssertPtrReturn(pcszSrc, VERR_INVALID_POINTER);
590 AssertReturn(cbSrc, VERR_INVALID_PARAMETER);
591 AssertPtrReturn(ppwszDst, VERR_INVALID_POINTER);
592 AssertPtrReturn(pcwDst, VERR_INVALID_POINTER);
593
594 int rc = VINF_SUCCESS;
595
596 PRTUTF16 pwszDst = NULL;
597
598 /* Calculate the space needed. */
599 unsigned cwDst = 0;
600 for (unsigned i = 0; i < cbSrc && pcszSrc[i] != '\0'; ++i)
601 {
602 if (pcszSrc[i] == VBOX_SHCL_LINEFEED)
603 cwDst += 2; /* Space for VBOX_SHCL_CARRIAGERETURN + VBOX_SHCL_LINEFEED. */
604 else
605 ++cwDst;
606 }
607
608 pwszDst = (PRTUTF16)RTMemAlloc((cwDst + 1 /* Leave space for the terminator */) * sizeof(RTUTF16));
609 if (!pwszDst)
610 rc = VERR_NO_MEMORY;
611
612 /* Do the conversion, bearing in mind that Latin-1 expands "naturally" to UTF-16. */
613 if (RT_SUCCESS(rc))
614 {
615 for (unsigned i = 0, j = 0; i < cbSrc; ++i, ++j)
616 {
617 if (pcszSrc[i] != VBOX_SHCL_LINEFEED)
618 pwszDst[j] = pcszSrc[i];
619 else
620 {
621 pwszDst[j] = VBOX_SHCL_CARRIAGERETURN;
622 pwszDst[j + 1] = VBOX_SHCL_LINEFEED;
623 ++j;
624 }
625 }
626
627 pwszDst[cwDst] = '\0'; /* Make sure we are zero-terminated. */
628 }
629
630 if (RT_SUCCESS(rc))
631 {
632 *ppwszDst = pwszDst;
633 *pcwDst = cwDst;
634 }
635 else
636 RTMemFree(pwszDst);
637
638 LogFlowFuncLeaveRC(rc);
639 return rc;
640}
641
642int ShClConvUtf16ToUtf8HTML(PCRTUTF16 pcwszSrc, size_t cwcSrc, char **ppszDst, size_t *pcbDst)
643{
644 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
645 AssertReturn (cwcSrc, VERR_INVALID_PARAMETER);
646 AssertPtrReturn(ppszDst, VERR_INVALID_POINTER);
647 AssertPtrReturn(pcbDst, VERR_INVALID_POINTER);
648
649 int rc = VINF_SUCCESS;
650
651 size_t cwTmp = cwcSrc;
652 PCRTUTF16 pwTmp = pcwszSrc;
653
654 char *pchDst = NULL;
655 size_t cbDst = 0;
656
657 size_t i = 0;
658 while (i < cwTmp)
659 {
660 /* Find zero symbol (end of string). */
661 for (; i < cwTmp && pcwszSrc[i] != 0; i++)
662 ;
663
664 /* Convert found string. */
665 char *psz = NULL;
666 size_t cch = 0;
667 rc = RTUtf16ToUtf8Ex(pwTmp, cwTmp, &psz, pwTmp - pcwszSrc, &cch);
668 if (RT_FAILURE(rc))
669 break;
670
671 /* Append new substring. */
672 char *pchNew = (char *)RTMemRealloc(pchDst, cbDst + cch + 1);
673 if (!pchNew)
674 {
675 RTStrFree(psz);
676 rc = VERR_NO_MEMORY;
677 break;
678 }
679
680 pchDst = pchNew;
681 memcpy(pchDst + cbDst, psz, cch + 1);
682
683 RTStrFree(psz);
684
685 cbDst += cch + 1;
686
687 /* Skip zero symbols. */
688 for (; i < cwTmp && pcwszSrc[i] == 0; i++)
689 ;
690
691 /* Remember start of string. */
692 pwTmp += i;
693 }
694
695 if (RT_SUCCESS(rc))
696 {
697 *ppszDst = pchDst;
698 *pcbDst = cbDst;
699
700 return VINF_SUCCESS;
701 }
702
703 RTMemFree(pchDst);
704
705 LogFlowFuncLeaveRC(rc);
706 return rc;
707}
708
709int ShClUtf16LFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwSrc, size_t *pchLen)
710{
711 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
712 AssertPtrReturn(pchLen, VERR_INVALID_POINTER);
713
714 AssertMsgReturn(pcwszSrc[0] != VBOX_SHCL_UTF16BEMARKER,
715 ("Big endian UTF-16 not supported yet\n"), VERR_NOT_SUPPORTED);
716
717 size_t cLen = 0;
718
719 /* Don't copy the endian marker. */
720 size_t i = pcwszSrc[0] == VBOX_SHCL_UTF16LEMARKER ? 1 : 0;
721
722 /* Calculate the size of the destination text string. */
723 /* Is this Utf16 or Utf16-LE? */
724 for (; i < cwSrc; ++i, ++cLen)
725 {
726 /* Check for a single line feed */
727 if (pcwszSrc[i] == VBOX_SHCL_LINEFEED)
728 ++cLen;
729#ifdef RT_OS_DARWIN
730 /* Check for a single carriage return (MacOS) */
731 if (pcwszSrc[i] == VBOX_SHCL_CARRIAGERETURN)
732 ++cLen;
733#endif
734 if (pcwszSrc[i] == 0)
735 {
736 /* Don't count this, as we do so below. */
737 break;
738 }
739 }
740
741 *pchLen = cLen;
742
743 LogFlowFuncLeaveRC(VINF_SUCCESS);
744 return VINF_SUCCESS;
745}
746
747int ShClUtf16CRLFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwSrc, size_t *pchLen)
748{
749 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
750 AssertReturn(cwSrc, VERR_INVALID_PARAMETER);
751 AssertPtrReturn(pchLen, VERR_INVALID_POINTER);
752
753 AssertMsgReturn(pcwszSrc[0] != VBOX_SHCL_UTF16BEMARKER,
754 ("Big endian UTF-16 not supported yet\n"), VERR_NOT_SUPPORTED);
755
756 size_t cLen = 0;
757
758 /* Calculate the size of the destination text string. */
759 /* Is this Utf16 or Utf16-LE? */
760 if (pcwszSrc[0] == VBOX_SHCL_UTF16LEMARKER)
761 cLen = 0;
762 else
763 cLen = 1;
764
765 for (size_t i = 0; i < cwSrc; ++i, ++cLen)
766 {
767 if ( (i + 1 < cwSrc)
768 && (pcwszSrc[i] == VBOX_SHCL_CARRIAGERETURN)
769 && (pcwszSrc[i + 1] == VBOX_SHCL_LINEFEED))
770 {
771 ++i;
772 }
773 if (pcwszSrc[i] == 0)
774 break;
775 }
776
777 *pchLen = cLen;
778
779 LogFlowFuncLeaveRC(VINF_SUCCESS);
780 return VINF_SUCCESS;
781}
782
783int ShClConvUtf16LFToCRLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pu16Dst, size_t cwDst)
784{
785 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
786 AssertPtrReturn(pu16Dst, VERR_INVALID_POINTER);
787 AssertReturn(cwDst, VERR_INVALID_PARAMETER);
788
789 AssertMsgReturn(pcwszSrc[0] != VBOX_SHCL_UTF16BEMARKER,
790 ("Big endian UTF-16 not supported yet\n"), VERR_NOT_SUPPORTED);
791
792 int rc = VINF_SUCCESS;
793
794 /* Don't copy the endian marker. */
795 size_t i = pcwszSrc[0] == VBOX_SHCL_UTF16LEMARKER ? 1 : 0;
796 size_t j = 0;
797
798 for (; i < cwcSrc; ++i, ++j)
799 {
800 /* Don't copy the null byte, as we add it below. */
801 if (pcwszSrc[i] == 0)
802 break;
803
804 /* Not enough space in destination? */
805 if (j == cwDst)
806 {
807 rc = VERR_BUFFER_OVERFLOW;
808 break;
809 }
810
811 if (pcwszSrc[i] == VBOX_SHCL_LINEFEED)
812 {
813 pu16Dst[j] = VBOX_SHCL_CARRIAGERETURN;
814 ++j;
815
816 /* Not enough space in destination? */
817 if (j == cwDst)
818 {
819 rc = VERR_BUFFER_OVERFLOW;
820 break;
821 }
822 }
823#ifdef RT_OS_DARWIN
824 /* Check for a single carriage return (MacOS) */
825 else if (pcwszSrc[i] == VBOX_SHCL_CARRIAGERETURN)
826 {
827 /* Set CR.r */
828 pu16Dst[j] = VBOX_SHCL_CARRIAGERETURN;
829 ++j;
830
831 /* Not enough space in destination? */
832 if (j == cwDst)
833 {
834 rc = VERR_BUFFER_OVERFLOW;
835 break;
836 }
837
838 /* Add line feed. */
839 pu16Dst[j] = VBOX_SHCL_LINEFEED;
840 continue;
841 }
842#endif
843 pu16Dst[j] = pcwszSrc[i];
844 }
845
846 if (j == cwDst)
847 rc = VERR_BUFFER_OVERFLOW;
848
849 if (RT_SUCCESS(rc))
850 {
851 /* Add terminator. */
852 pu16Dst[j] = 0;
853 }
854
855 LogFlowFuncLeaveRC(rc);
856 return rc;
857}
858
859int ShClConvUtf16CRLFToLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pu16Dst, size_t cwDst)
860{
861 AssertPtrReturn(pcwszSrc, VERR_INVALID_POINTER);
862 AssertReturn(cwcSrc, VERR_INVALID_PARAMETER);
863 AssertPtrReturn(pu16Dst, VERR_INVALID_POINTER);
864 AssertReturn(cwDst, VERR_INVALID_PARAMETER);
865
866 AssertMsgReturn(pcwszSrc[0] != VBOX_SHCL_UTF16BEMARKER,
867 ("Big endian UTF-16 not supported yet\n"), VERR_NOT_SUPPORTED);
868
869 /* Prepend the Utf16 byte order marker if it is missing. */
870 size_t cwDstPos;
871 if (pcwszSrc[0] == VBOX_SHCL_UTF16LEMARKER)
872 {
873 cwDstPos = 0;
874 }
875 else
876 {
877 pu16Dst[0] = VBOX_SHCL_UTF16LEMARKER;
878 cwDstPos = 1;
879 }
880
881 for (size_t i = 0; i < cwcSrc; ++i, ++cwDstPos)
882 {
883 if (pcwszSrc[i] == 0)
884 break;
885
886 if (cwDstPos == cwDst)
887 return VERR_BUFFER_OVERFLOW;
888
889 if ( (i + 1 < cwcSrc)
890 && (pcwszSrc[i] == VBOX_SHCL_CARRIAGERETURN)
891 && (pcwszSrc[i + 1] == VBOX_SHCL_LINEFEED))
892 {
893 ++i;
894 }
895
896 pu16Dst[cwDstPos] = pcwszSrc[i];
897 }
898
899 if (cwDstPos == cwDst)
900 return VERR_BUFFER_OVERFLOW;
901
902 /* Add terminating zero. */
903 pu16Dst[cwDstPos] = 0;
904
905 LogFlowFuncLeaveRC(VINF_SUCCESS);
906 return VINF_SUCCESS;
907}
908
909int ShClDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDest, size_t *pcbDest)
910{
911 AssertPtrReturn(pvSrc, VERR_INVALID_POINTER);
912 AssertReturn(cbSrc, VERR_INVALID_PARAMETER);
913 AssertPtrReturn(ppvDest, VERR_INVALID_POINTER);
914 AssertPtrReturn(pcbDest, VERR_INVALID_POINTER);
915
916 PBMPWIN3XINFOHDR coreHdr = (PBMPWIN3XINFOHDR)pvSrc;
917 /** @todo Support all the many versions of the DIB headers. */
918 if ( cbSrc < sizeof(BMPWIN3XINFOHDR)
919 || RT_LE2H_U32(coreHdr->cbSize) < sizeof(BMPWIN3XINFOHDR)
920 || RT_LE2H_U32(coreHdr->cbSize) != sizeof(BMPWIN3XINFOHDR))
921 {
922 return VERR_INVALID_PARAMETER;
923 }
924
925 size_t offPixel = sizeof(BMPFILEHDR)
926 + RT_LE2H_U32(coreHdr->cbSize)
927 + RT_LE2H_U32(coreHdr->cClrUsed) * sizeof(uint32_t);
928 if (cbSrc < offPixel)
929 return VERR_INVALID_PARAMETER;
930
931 size_t cbDst = sizeof(BMPFILEHDR) + cbSrc;
932
933 void *pvDest = RTMemAlloc(cbDst);
934 if (!pvDest)
935 return VERR_NO_MEMORY;
936
937 PBMPFILEHDR fileHdr = (PBMPFILEHDR)pvDest;
938
939 fileHdr->uType = BMP_HDR_MAGIC;
940 fileHdr->cbFileSize = (uint32_t)RT_H2LE_U32(cbDst);
941 fileHdr->Reserved1 = 0;
942 fileHdr->Reserved2 = 0;
943 fileHdr->offBits = (uint32_t)RT_H2LE_U32(offPixel);
944
945 memcpy((uint8_t *)pvDest + sizeof(BMPFILEHDR), pvSrc, cbSrc);
946
947 *ppvDest = pvDest;
948 *pcbDest = cbDst;
949
950 LogFlowFuncLeaveRC(VINF_SUCCESS);
951 return VINF_SUCCESS;
952}
953
954int ShClBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDest, size_t *pcbDest)
955{
956 AssertPtrReturn(pvSrc, VERR_INVALID_POINTER);
957 AssertReturn(cbSrc, VERR_INVALID_PARAMETER);
958 AssertPtrReturn(ppvDest, VERR_INVALID_POINTER);
959 AssertPtrReturn(pcbDest, VERR_INVALID_POINTER);
960
961 PBMPFILEHDR pBmpHdr = (PBMPFILEHDR)pvSrc;
962 if ( cbSrc < sizeof(BMPFILEHDR)
963 || pBmpHdr->uType != BMP_HDR_MAGIC
964 || RT_LE2H_U32(pBmpHdr->cbFileSize) != cbSrc)
965 {
966 return VERR_INVALID_PARAMETER;
967 }
968
969 *ppvDest = ((uint8_t *)pvSrc) + sizeof(BMPFILEHDR);
970 *pcbDest = cbSrc - sizeof(BMPFILEHDR);
971
972 return VINF_SUCCESS;
973}
974
975#ifdef LOG_ENABLED
976
977int ShClDbgDumpHtml(const char *pcszSrc, size_t cbSrc)
978{
979 int rc = VINF_SUCCESS;
980 char *pszBuf = (char *)RTMemTmpAllocZ(cbSrc + 1);
981 if (pszBuf)
982 {
983 memcpy(pszBuf, pcszSrc, cbSrc);
984 pszBuf[cbSrc] = '\0';
985 for (size_t off = 0; off < cbSrc; ++off)
986 if (pszBuf[off] == '\n' || pszBuf[off] == '\r')
987 pszBuf[off] = ' ';
988 LogFunc(("Removed \\r\\n: %s\n", pszBuf));
989 RTMemTmpFree(pszBuf);
990 }
991 else
992 rc = VERR_NO_MEMORY;
993 return rc;
994}
995
996void ShClDbgDumpData(const void *pv, size_t cb, SHCLFORMAT uFormat)
997{
998 if (LogIsEnabled())
999 {
1000 if (uFormat & VBOX_SHCL_FMT_UNICODETEXT)
1001 {
1002 LogFunc(("VBOX_SHCL_FMT_UNICODETEXT:\n"));
1003 if (pv && cb)
1004 LogFunc(("%ls\n", pv));
1005 else
1006 LogFunc(("%p %zu\n", pv, cb));
1007 }
1008 else if (uFormat & VBOX_SHCL_FMT_BITMAP)
1009 LogFunc(("VBOX_SHCL_FMT_BITMAP\n"));
1010 else if (uFormat & VBOX_SHCL_FMT_HTML)
1011 {
1012 LogFunc(("VBOX_SHCL_FMT_HTML:\n"));
1013 if (pv && cb)
1014 {
1015 LogFunc(("%s\n", pv));
1016 ShClDbgDumpHtml((const char *)pv, cb);
1017 }
1018 else
1019 LogFunc(("%p %zu\n", pv, cb));
1020 }
1021 else
1022 LogFunc(("Invalid format %02X\n", uFormat));
1023 }
1024}
1025
1026#endif /* LOG_ENABLED */
1027
1028/**
1029 * Translates a Shared Clipboard host function number to a string.
1030 *
1031 * @returns Function ID string name.
1032 * @param uFn The function to translate.
1033 */
1034const char *ShClHostFunctionToStr(uint32_t uFn)
1035{
1036 switch (uFn)
1037 {
1038 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_SET_MODE);
1039 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE);
1040 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_SET_HEADLESS);
1041 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_CANCEL);
1042 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_ERROR);
1043 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_AREA_REGISTER);
1044 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_AREA_UNREGISTER);
1045 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_AREA_ATTACH);
1046 RT_CASE_RET_STR(VBOX_SHCL_HOST_FN_AREA_DETACH);
1047 }
1048 return "Unknown";
1049}
1050
1051/**
1052 * Translates a Shared Clipboard host message enum to a string.
1053 *
1054 * @returns Message ID string name.
1055 * @param uMsg The message to translate.
1056 */
1057const char *ShClHostMsgToStr(uint32_t uMsg)
1058{
1059 switch (uMsg)
1060 {
1061 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_QUIT);
1062 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_READ_DATA);
1063 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
1064 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_CANCELED);
1065 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_READ_DATA_CID);
1066 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
1067 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
1068 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_WRITE);
1069 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
1070 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_WRITE);
1071 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1072 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1073 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1074 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_WRITE);
1075 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1076 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_WRITE);
1077 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1078 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1079 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1080 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE);
1081 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_CANCEL);
1082 RT_CASE_RET_STR(VBOX_SHCL_HOST_MSG_TRANSFER_ERROR);
1083 }
1084 return "Unknown";
1085}
1086
1087/**
1088 * Translates a Shared Clipboard guest message enum to a string.
1089 *
1090 * @returns Message ID string name.
1091 * @param uMsg The message to translate.
1092 */
1093const char *ShClGuestMsgToStr(uint32_t uMsg)
1094{
1095 switch (uMsg)
1096 {
1097 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT);
1098 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_REPORT_FORMATS);
1099 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_DATA_READ);
1100 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_DATA_WRITE);
1101 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_CONNECT);
1102 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_REPORT_FEATURES);
1103 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_QUERY_FEATURES);
1104 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT);
1105 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT);
1106 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_MSG_GET);
1107 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_MSG_CANCEL);
1108 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_REPLY);
1109 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ);
1110 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE);
1111 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ);
1112 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE);
1113 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_LIST_OPEN);
1114 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_LIST_CLOSE);
1115 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_LIST_HDR_READ);
1116 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE);
1117 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ);
1118 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE);
1119 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_OBJ_OPEN);
1120 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_OBJ_CLOSE);
1121 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_OBJ_READ);
1122 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_OBJ_WRITE);
1123 RT_CASE_RET_STR(VBOX_SHCL_GUEST_FN_ERROR);
1124 }
1125 return "Unknown";
1126}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette