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