/* * Deskflow -- mouse and keyboard sharing utility * SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception */ #include "platform/XWindowsClipboardAnyBitmapConverter.h" // BMP info header structure struct CBMPInfoHeader { public: uint32_t biSize; int32_t biWidth; int32_t biHeight; uint16_t biPlanes; uint16_t biBitCount; uint32_t biCompression; uint32_t biSizeImage; int32_t biXPelsPerMeter; int32_t biYPelsPerMeter; uint32_t biClrUsed; uint32_t biClrImportant; }; // BMP is little-endian static void toLE(uint8_t *&dst, uint16_t src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst += 2; } static void toLE(uint8_t *&dst, int32_t src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst[2] = static_cast((src >> 16) & 0xffu); dst[3] = static_cast((src >> 24) & 0xffu); dst += 4; } static void toLE(uint8_t *&dst, uint32_t src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst[2] = static_cast((src >> 16) & 0xffu); dst[3] = static_cast((src >> 24) & 0xffu); dst += 4; } static inline uint16_t fromLEU16(const uint8_t *data) { return static_cast(data[0]) | (static_cast(data[1]) << 8); } static inline int32_t fromLES32(const uint8_t *data) { return static_cast( static_cast(data[0]) | (static_cast(data[1]) << 8) | (static_cast(data[2]) << 16) | (static_cast(data[3]) << 24) ); } static inline uint32_t fromLEU32(const uint8_t *data) { return static_cast(data[0]) | (static_cast(data[1]) << 8) | (static_cast(data[2]) << 16) | (static_cast(data[3]) << 24); } // // XWindowsClipboardAnyBitmapConverter // IClipboard::Format XWindowsClipboardAnyBitmapConverter::getFormat() const { return IClipboard::Format::Bitmap; } int XWindowsClipboardAnyBitmapConverter::getDataSize() const { return 8; } std::string XWindowsClipboardAnyBitmapConverter::fromIClipboard(const std::string &bmp) const { // fill BMP info header with native-endian data CBMPInfoHeader infoHeader; const auto *rawBMPInfoHeader = reinterpret_cast(bmp.data()); infoHeader.biSize = fromLEU32(rawBMPInfoHeader + 0); infoHeader.biWidth = fromLES32(rawBMPInfoHeader + 4); infoHeader.biHeight = fromLES32(rawBMPInfoHeader + 8); infoHeader.biPlanes = fromLEU16(rawBMPInfoHeader + 12); infoHeader.biBitCount = fromLEU16(rawBMPInfoHeader + 14); infoHeader.biCompression = fromLEU32(rawBMPInfoHeader + 16); infoHeader.biSizeImage = fromLEU32(rawBMPInfoHeader + 20); infoHeader.biXPelsPerMeter = fromLES32(rawBMPInfoHeader + 24); infoHeader.biYPelsPerMeter = fromLES32(rawBMPInfoHeader + 28); infoHeader.biClrUsed = fromLEU32(rawBMPInfoHeader + 32); infoHeader.biClrImportant = fromLEU32(rawBMPInfoHeader + 36); // check that format is acceptable if (infoHeader.biSize != 40 || infoHeader.biWidth == 0 || infoHeader.biHeight == 0 || infoHeader.biPlanes != 0 || infoHeader.biCompression != 0 || (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32)) { return std::string(); } // convert to image format const uint8_t *rawBMPPixels = rawBMPInfoHeader + 40; if (infoHeader.biBitCount == 24) { return doBGRFromIClipboard(rawBMPPixels, infoHeader.biWidth, infoHeader.biHeight); } else { return doBGRAFromIClipboard(rawBMPPixels, infoHeader.biWidth, infoHeader.biHeight); } } std::string XWindowsClipboardAnyBitmapConverter::toIClipboard(const std::string &image) const { // convert to raw BMP data uint32_t w; uint32_t h; uint32_t depth; std::string rawBMP = doToIClipboard(image, w, h, depth); if (rawBMP.empty() || w == 0 || h == 0 || (depth != 24 && depth != 32)) { return std::string(); } // fill BMP info header with little-endian data uint8_t infoHeader[40]; uint8_t *dst = infoHeader; toLE(dst, static_cast(40)); toLE(dst, static_cast(w)); toLE(dst, static_cast(h)); toLE(dst, static_cast(1)); toLE(dst, static_cast(depth)); toLE(dst, static_cast(0)); // BI_RGB toLE(dst, static_cast(image.size())); toLE(dst, static_cast(2834)); // 72 dpi toLE(dst, static_cast(2834)); // 72 dpi toLE(dst, static_cast(0)); toLE(dst, static_cast(0)); // construct image return std::string(reinterpret_cast(infoHeader), sizeof(infoHeader)) + rawBMP; }