summaryrefslogtreecommitdiffstats
path: root/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp')
-rw-r--r--src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp b/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
new file mode 100644
index 00000000..1da319c3
--- /dev/null
+++ b/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp
@@ -0,0 +1,337 @@
+/* $Id: clipboard-helper.cpp $ */
+/** @file
+ * Shared Clipboard: Some helper function for converting between the various eol.
+ */
+
+/*
+ * Includes contributions from François Revol
+ *
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <iprt/alloc.h>
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <VBox/log.h>
+#include <VBox/GuestHost/clipboard-helper.h>
+
+/** @todo use const where appropriate; delinuxify the code (*Lin* -> *Host*); use AssertLogRel*. */
+
+int vboxClipboardUtf16GetWinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
+{
+ size_t cwDest, i;
+
+ LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
+ AssertLogRelMsgReturn(pwszSrc != NULL, ("vboxClipboardUtf16GetWinSize: received a null Utf16 string, returning VERR_INVALID_PARAMETER\n"), VERR_INVALID_PARAMETER);
+ if (cwSrc == 0)
+ {
+ *pcwDest = 0;
+ LogFlowFunc(("empty source string, returning\n"));
+ return VINF_SUCCESS;
+ }
+/** @todo convert the remainder of the Assert stuff to AssertLogRel. */
+ /* We only take little endian Utf16 */
+ if (pwszSrc[0] == UTF16BEMARKER)
+ {
+ LogRel(("vboxClipboardUtf16GetWinSize: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
+ AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
+ }
+ cwDest = 0;
+ /* Calculate the size of the destination text string. */
+ /* Is this Utf16 or Utf16-LE? */
+ for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0); i < cwSrc; ++i, ++cwDest)
+ {
+ /* Check for a single line feed */
+ if (pwszSrc[i] == LINEFEED)
+ ++cwDest;
+#ifdef RT_OS_DARWIN
+ /* Check for a single carriage return (MacOS) */
+ if (pwszSrc[i] == CARRIAGERETURN)
+ ++cwDest;
+#endif
+ if (pwszSrc[i] == 0)
+ {
+ /* Don't count this, as we do so below. */
+ break;
+ }
+ }
+ /* Count the terminating null byte. */
+ ++cwDest;
+ LogFlowFunc(("returning VINF_SUCCESS, %d 16bit words\n", cwDest));
+ *pcwDest = cwDest;
+ return VINF_SUCCESS;
+}
+
+int vboxClipboardUtf16LinToWin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
+ size_t cwDest)
+{
+ size_t i, j;
+ LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
+ if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
+ {
+ LogRel(("vboxClipboardUtf16LinToWin: received an invalid pointer, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
+ AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
+ }
+ if (cwSrc == 0)
+ {
+ if (cwDest == 0)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ pu16Dest[0] = 0;
+ LogFlowFunc(("empty source string, returning\n"));
+ return VINF_SUCCESS;
+ }
+ /* We only take little endian Utf16 */
+ if (pwszSrc[0] == UTF16BEMARKER)
+ {
+ LogRel(("vboxClipboardUtf16LinToWin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
+ AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
+ }
+ /* Don't copy the endian marker. */
+ for (i = (pwszSrc[0] == UTF16LEMARKER ? 1 : 0), j = 0; i < cwSrc; ++i, ++j)
+ {
+ /* Don't copy the null byte, as we add it below. */
+ if (pwszSrc[i] == 0)
+ break;
+ if (j == cwDest)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ if (pwszSrc[i] == LINEFEED)
+ {
+ pu16Dest[j] = CARRIAGERETURN;
+ ++j;
+ if (j == cwDest)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ }
+#ifdef RT_OS_DARWIN
+ /* Check for a single carriage return (MacOS) */
+ else if (pwszSrc[i] == CARRIAGERETURN)
+ {
+ /* set cr */
+ pu16Dest[j] = CARRIAGERETURN;
+ ++j;
+ if (j == cwDest)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ /* add the lf */
+ pu16Dest[j] = LINEFEED;
+ continue;
+ }
+#endif
+ pu16Dest[j] = pwszSrc[i];
+ }
+ /* Add the trailing null. */
+ if (j == cwDest)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ pu16Dest[j] = 0;
+ LogFlowFunc(("rc=VINF_SUCCESS, pu16Dest=%ls\n", pu16Dest));
+ return VINF_SUCCESS;
+}
+
+int vboxClipboardUtf16GetLinSize(PRTUTF16 pwszSrc, size_t cwSrc, size_t *pcwDest)
+{
+ size_t cwDest;
+
+ LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u\n", cwSrc, pwszSrc, cwSrc));
+ if (!VALID_PTR(pwszSrc))
+ {
+ LogRel(("vboxClipboardUtf16GetLinSize: received an invalid Utf16 string %p. Returning VERR_INVALID_PARAMETER.\n", pwszSrc));
+ AssertReturn(VALID_PTR(pwszSrc), VERR_INVALID_PARAMETER);
+ }
+ if (cwSrc == 0)
+ {
+ LogFlowFunc(("empty source string, returning VINF_SUCCESS\n"));
+ *pcwDest = 0;
+ return VINF_SUCCESS;
+ }
+ /* We only take little endian Utf16 */
+ if (pwszSrc[0] == UTF16BEMARKER)
+ {
+ LogRel(("vboxClipboardUtf16GetLinSize: received a big endian Utf16 string. Returning VERR_INVALID_PARAMETER.\n"));
+ AssertReturn(pwszSrc[0] != UTF16BEMARKER, VERR_INVALID_PARAMETER);
+ }
+ /* Calculate the size of the destination text string. */
+ /* Is this Utf16 or Utf16-LE? */
+ if (pwszSrc[0] == UTF16LEMARKER)
+ cwDest = 0;
+ else
+ cwDest = 1;
+ for (size_t i = 0; i < cwSrc; ++i, ++cwDest)
+ {
+ if ( (i + 1 < cwSrc)
+ && (pwszSrc[i] == CARRIAGERETURN)
+ && (pwszSrc[i + 1] == LINEFEED))
+ {
+ ++i;
+ }
+ if (pwszSrc[i] == 0)
+ {
+ break;
+ }
+ }
+ /* Terminating zero */
+ ++cwDest;
+ LogFlowFunc(("returning %d\n", cwDest));
+ *pcwDest = cwDest;
+ return VINF_SUCCESS;
+}
+
+int vboxClipboardUtf16WinToLin(PRTUTF16 pwszSrc, size_t cwSrc, PRTUTF16 pu16Dest,
+ size_t cwDest)
+{
+ size_t cwDestPos;
+
+ LogFlowFunc(("pwszSrc=%.*ls, cwSrc=%u, pu16Dest=%p, cwDest=%u\n",
+ cwSrc, pwszSrc, cwSrc, pu16Dest, cwDest));
+ /* A buffer of size 0 may not be an error, but it is not a good idea either. */
+ Assert(cwDest > 0);
+ if (!VALID_PTR(pwszSrc) || !VALID_PTR(pu16Dest))
+ {
+ LogRel(("vboxClipboardUtf16WinToLin: received an invalid ptr, pwszSrc=%p, pu16Dest=%p, returning VERR_INVALID_PARAMETER\n", pwszSrc, pu16Dest));
+ AssertReturn(VALID_PTR(pwszSrc) && VALID_PTR(pu16Dest), VERR_INVALID_PARAMETER);
+ }
+ /* We only take little endian Utf16 */
+ if (pwszSrc[0] == UTF16BEMARKER)
+ {
+ LogRel(("vboxClipboardUtf16WinToLin: received a big endian Utf16 string, returning VERR_INVALID_PARAMETER\n"));
+ AssertMsgFailedReturn(("received a big endian string\n"), VERR_INVALID_PARAMETER);
+ }
+ if (cwDest == 0)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ if (cwSrc == 0)
+ {
+ pu16Dest[0] = 0;
+ LogFlowFunc(("received empty string. Returning VINF_SUCCESS\n"));
+ return VINF_SUCCESS;
+ }
+ /* Prepend the Utf16 byte order marker if it is missing. */
+ if (pwszSrc[0] == UTF16LEMARKER)
+ {
+ cwDestPos = 0;
+ }
+ else
+ {
+ pu16Dest[0] = UTF16LEMARKER;
+ cwDestPos = 1;
+ }
+ for (size_t i = 0; i < cwSrc; ++i, ++cwDestPos)
+ {
+ if (pwszSrc[i] == 0)
+ {
+ break;
+ }
+ if (cwDestPos == cwDest)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ if ( (i + 1 < cwSrc)
+ && (pwszSrc[i] == CARRIAGERETURN)
+ && (pwszSrc[i + 1] == LINEFEED))
+ {
+ ++i;
+ }
+ pu16Dest[cwDestPos] = pwszSrc[i];
+ }
+ /* Terminating zero */
+ if (cwDestPos == cwDest)
+ {
+ LogFlowFunc(("returning VERR_BUFFER_OVERFLOW\n"));
+ return VERR_BUFFER_OVERFLOW;
+ }
+ pu16Dest[cwDestPos] = 0;
+ LogFlowFunc(("set string %ls. Returning\n", pu16Dest + 1));
+ return VINF_SUCCESS;
+}
+
+int vboxClipboardDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDest, size_t *pcbDest)
+{
+ size_t cb = sizeof(BMFILEHEADER) + cbSrc;
+ PBMFILEHEADER pFileHeader = NULL;
+ void *pvDest = NULL;
+ size_t offPixel = 0;
+
+ AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
+
+ PBMINFOHEADER pBitmapInfoHeader = (PBMINFOHEADER)pvSrc;
+ /** @todo Support all the many versions of the DIB headers. */
+ if ( cbSrc < sizeof(BMINFOHEADER)
+ || RT_LE2H_U32(pBitmapInfoHeader->u32Size) < sizeof(BMINFOHEADER)
+ || RT_LE2H_U32(pBitmapInfoHeader->u32Size) != sizeof(BMINFOHEADER))
+ {
+ Log(("vboxClipboardDibToBmp: invalid or unsupported bitmap data.\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ offPixel = sizeof(BMFILEHEADER)
+ + RT_LE2H_U32(pBitmapInfoHeader->u32Size)
+ + RT_LE2H_U32(pBitmapInfoHeader->u32ClrUsed) * sizeof(uint32_t);
+ if (cbSrc < offPixel)
+ {
+ Log(("vboxClipboardDibToBmp: invalid bitmap data.\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ pvDest = RTMemAlloc(cb);
+ if (!pvDest)
+ {
+ Log(("writeToPasteboard: cannot allocate memory for bitmap.\n"));
+ return VERR_NO_MEMORY;
+ }
+
+ pFileHeader = (PBMFILEHEADER)pvDest;
+ pFileHeader->u16Type = BITMAPHEADERMAGIC;
+ pFileHeader->u32Size = RT_H2LE_U32(cb);
+ pFileHeader->u16Reserved1 = pFileHeader->u16Reserved2 = 0;
+ pFileHeader->u32OffBits = RT_H2LE_U32(offPixel);
+ memcpy((uint8_t *)pvDest + sizeof(BMFILEHEADER), pvSrc, cbSrc);
+ *ppvDest = pvDest;
+ *pcbDest = cb;
+ return VINF_SUCCESS;
+}
+
+int vboxClipboardBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDest, size_t *pcbDest)
+{
+ AssertPtrReturn(pvSrc, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(ppvDest, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pcbDest, VERR_INVALID_PARAMETER);
+
+ PBMFILEHEADER pFileHeader = (PBMFILEHEADER)pvSrc;
+ if ( cbSrc < sizeof(BMFILEHEADER)
+ || pFileHeader->u16Type != BITMAPHEADERMAGIC
+ || RT_LE2H_U32(pFileHeader->u32Size) != cbSrc)
+ {
+ Log(("vboxClipboardBmpGetDib: invalid bitmap data.\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ *ppvDest = ((uint8_t *)pvSrc) + sizeof(BMFILEHEADER);
+ *pcbDest = cbSrc - sizeof(BMFILEHEADER);
+ return VINF_SUCCESS;
+}
+