1 /*
2 * barrier -- mouse and keyboard sharing utility
3 * Copyright (C) 2012-2016 Symless Ltd.
4 * Copyright (C) 2004 Chris Schoeneman
5 *
6 * This package is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * found in the file LICENSE that should have accompanied this file.
9 *
10 * This package is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "platform/XWindowsClipboardAnyBitmapConverter.h"
20
21 // BMP info header structure
22 struct CBMPInfoHeader {
23 public:
24 UInt32 biSize;
25 SInt32 biWidth;
26 SInt32 biHeight;
27 UInt16 biPlanes;
28 UInt16 biBitCount;
29 UInt32 biCompression;
30 UInt32 biSizeImage;
31 SInt32 biXPelsPerMeter;
32 SInt32 biYPelsPerMeter;
33 UInt32 biClrUsed;
34 UInt32 biClrImportant;
35 };
36
37 // BMP is little-endian
38
39 static
40 void
toLE(UInt8 * & dst,UInt16 src)41 toLE(UInt8*& dst, UInt16 src)
42 {
43 dst[0] = static_cast<UInt8>(src & 0xffu);
44 dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
45 dst += 2;
46 }
47
48 static
49 void
toLE(UInt8 * & dst,SInt32 src)50 toLE(UInt8*& dst, SInt32 src)
51 {
52 dst[0] = static_cast<UInt8>(src & 0xffu);
53 dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
54 dst[2] = static_cast<UInt8>((src >> 16) & 0xffu);
55 dst[3] = static_cast<UInt8>((src >> 24) & 0xffu);
56 dst += 4;
57 }
58
59 static
60 void
toLE(UInt8 * & dst,UInt32 src)61 toLE(UInt8*& dst, UInt32 src)
62 {
63 dst[0] = static_cast<UInt8>(src & 0xffu);
64 dst[1] = static_cast<UInt8>((src >> 8) & 0xffu);
65 dst[2] = static_cast<UInt8>((src >> 16) & 0xffu);
66 dst[3] = static_cast<UInt8>((src >> 24) & 0xffu);
67 dst += 4;
68 }
69
70 static inline
71 UInt16
fromLEU16(const UInt8 * data)72 fromLEU16(const UInt8* data)
73 {
74 return static_cast<UInt16>(data[0]) |
75 (static_cast<UInt16>(data[1]) << 8);
76 }
77
78 static inline
79 SInt32
fromLES32(const UInt8 * data)80 fromLES32(const UInt8* data)
81 {
82 return static_cast<SInt32>(static_cast<UInt32>(data[0]) |
83 (static_cast<UInt32>(data[1]) << 8) |
84 (static_cast<UInt32>(data[2]) << 16) |
85 (static_cast<UInt32>(data[3]) << 24));
86 }
87
88 static inline
89 UInt32
fromLEU32(const UInt8 * data)90 fromLEU32(const UInt8* data)
91 {
92 return static_cast<UInt32>(data[0]) |
93 (static_cast<UInt32>(data[1]) << 8) |
94 (static_cast<UInt32>(data[2]) << 16) |
95 (static_cast<UInt32>(data[3]) << 24);
96 }
97
98
99 //
100 // XWindowsClipboardAnyBitmapConverter
101 //
102
XWindowsClipboardAnyBitmapConverter()103 XWindowsClipboardAnyBitmapConverter::XWindowsClipboardAnyBitmapConverter()
104 {
105 // do nothing
106 }
107
~XWindowsClipboardAnyBitmapConverter()108 XWindowsClipboardAnyBitmapConverter::~XWindowsClipboardAnyBitmapConverter()
109 {
110 // do nothing
111 }
112
113 IClipboard::EFormat
getFormat() const114 XWindowsClipboardAnyBitmapConverter::getFormat() const
115 {
116 return IClipboard::kBitmap;
117 }
118
119 int
getDataSize() const120 XWindowsClipboardAnyBitmapConverter::getDataSize() const
121 {
122 return 8;
123 }
124
fromIClipboard(const std::string & bmp) const125 std::string XWindowsClipboardAnyBitmapConverter::fromIClipboard(const std::string& bmp) const
126 {
127 // fill BMP info header with native-endian data
128 CBMPInfoHeader infoHeader;
129 const UInt8* rawBMPInfoHeader = reinterpret_cast<const UInt8*>(bmp.data());
130 infoHeader.biSize = fromLEU32(rawBMPInfoHeader + 0);
131 infoHeader.biWidth = fromLES32(rawBMPInfoHeader + 4);
132 infoHeader.biHeight = fromLES32(rawBMPInfoHeader + 8);
133 infoHeader.biPlanes = fromLEU16(rawBMPInfoHeader + 12);
134 infoHeader.biBitCount = fromLEU16(rawBMPInfoHeader + 14);
135 infoHeader.biCompression = fromLEU32(rawBMPInfoHeader + 16);
136 infoHeader.biSizeImage = fromLEU32(rawBMPInfoHeader + 20);
137 infoHeader.biXPelsPerMeter = fromLES32(rawBMPInfoHeader + 24);
138 infoHeader.biYPelsPerMeter = fromLES32(rawBMPInfoHeader + 28);
139 infoHeader.biClrUsed = fromLEU32(rawBMPInfoHeader + 32);
140 infoHeader.biClrImportant = fromLEU32(rawBMPInfoHeader + 36);
141
142 // check that format is acceptable
143 if (infoHeader.biSize != 40 ||
144 infoHeader.biWidth == 0 || infoHeader.biHeight == 0 ||
145 infoHeader.biPlanes != 0 || infoHeader.biCompression != 0 ||
146 (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32)) {
147 return {};
148 }
149
150 // convert to image format
151 const UInt8* rawBMPPixels = rawBMPInfoHeader + 40;
152 if (infoHeader.biBitCount == 24) {
153 return doBGRFromIClipboard(rawBMPPixels,
154 infoHeader.biWidth, infoHeader.biHeight);
155 }
156 else {
157 return doBGRAFromIClipboard(rawBMPPixels,
158 infoHeader.biWidth, infoHeader.biHeight);
159 }
160 }
161
toIClipboard(const std::string & image) const162 std::string XWindowsClipboardAnyBitmapConverter::toIClipboard(const std::string& image) const
163 {
164 // convert to raw BMP data
165 UInt32 w, h, depth;
166 std::string rawBMP = doToIClipboard(image, w, h, depth);
167 if (rawBMP.empty() || w == 0 || h == 0 || (depth != 24 && depth != 32)) {
168 return {};
169 }
170
171 // fill BMP info header with little-endian data
172 UInt8 infoHeader[40];
173 UInt8* dst = infoHeader;
174 toLE(dst, static_cast<UInt32>(40));
175 toLE(dst, static_cast<SInt32>(w));
176 toLE(dst, static_cast<SInt32>(h));
177 toLE(dst, static_cast<UInt16>(1));
178 toLE(dst, static_cast<UInt16>(depth));
179 toLE(dst, static_cast<UInt32>(0)); // BI_RGB
180 toLE(dst, static_cast<UInt32>(image.size()));
181 toLE(dst, static_cast<SInt32>(2834)); // 72 dpi
182 toLE(dst, static_cast<SInt32>(2834)); // 72 dpi
183 toLE(dst, static_cast<UInt32>(0));
184 toLE(dst, static_cast<UInt32>(0));
185
186 // construct image
187 return std::string(reinterpret_cast<const char*>(infoHeader),
188 sizeof(infoHeader)) + rawBMP;
189 }
190