diff options
Diffstat (limited to 'src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp')
-rw-r--r-- | src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp | 337 |
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; +} + |