GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/copynpaste.cpp Lines: 0 69 0.0 %
Date: 2017-11-29 Branches: 0 44 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2001-2010  Wormux Team
4
 *  Copyright (C) 2011-2017  The ManaPlus Developers
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
/*
23
 *  IMPORTANT!
24
 *
25
 *  This code was taken from Wormux svn trunk at Feb 25 2010. Please don't
26
 *  make any unnecessary modifications, and try to sync up modifications
27
 *  when possible.
28
 */
29
30
#ifdef _MSC_VER
31
# include "msvc/config.h"
32
#elif defined(HAVE_CONFIG_H)
33
#include "config.h"
34
#endif  // _MSC_VER
35
36
#include "utils/copynpaste.h"
37
38
#include "debug.h"
39
40
#ifdef USE_SDL2
41
PRAGMA48(GCC diagnostic push)
42
PRAGMA48(GCC diagnostic ignored "-Wshadow")
43
#include <SDL_clipboard.h>
44
PRAGMA48(GCC diagnostic pop)
45
46
#else  // USE_SDL2
47
48
#if defined(__APPLE__)
49
#ifdef Status
50
#undef Status
51
#endif  // Status
52
#include <Carbon/Carbon.h>
53
#elif defined USE_X11
54
#include "render/graphics.h"
55
56
#include "utils/sdlhelper.h"
57
58
PRAGMA48(GCC diagnostic push)
59
PRAGMA48(GCC diagnostic ignored "-Wshadow")
60
#include <SDL_syswm.h>
61
PRAGMA48(GCC diagnostic pop)
62
#include <unistd.h>
63
#elif defined __native_client__
64
#include "utils/naclmessages.h"
65
#elif defined WIN32
66
#include "utils/cast.h"
67
PRAGMA48(GCC diagnostic push)
68
PRAGMA48(GCC diagnostic ignored "-Wshadow")
69
#include <SDL_syswm.h>
70
PRAGMA48(GCC diagnostic pop)
71
#endif  // defined(__APPLE__)
72
73
#endif  // USE_SDL2
74
75
#ifdef USE_SDL2
76
bool retrieveBuffer(std::string& text, size_t& pos)
77
{
78
    char *buf = SDL_GetClipboardText();
79
    if (buf)
80
    {
81
        text.insert(pos, buf);
82
        pos += strlen(buf);
83
        SDL_free(buf);
84
        return true;
85
    }
86
    return false;
87
}
88
89
bool sendBuffer(const std::string &restrict text)
90
{
91
    return !SDL_SetClipboardText(text.c_str());
92
}
93
94
#else  //  USE_SDL2
95
96
#ifdef WIN32
97
bool retrieveBuffer(std::string& text, size_t& pos)
98
{
99
    bool ret = false;
100
101
    if (!OpenClipboard(nullptr))
102
        return false;
103
104
    HANDLE h = GetClipboardData(CF_UNICODETEXT);
105
    if (h)
106
    {
107
        LPCWSTR data = static_cast<LPCWSTR>(GlobalLock(h));
108
109
        if (data)
110
        {
111
            const size_t len = WideCharToMultiByte(CP_UTF8, 0, data, -1,
112
                nullptr, 0, nullptr, nullptr);
113
            if (len > 0)
114
            {
115
                // Convert from UTF-16 to UTF-8
116
                void *temp = calloc(len, 1);
117
                if (WideCharToMultiByte(CP_UTF8, 0, data, -1,
118
                    static_cast<LPSTR>(temp), len, nullptr, nullptr))
119
                {
120
                    text.insert(pos, static_cast<char*>(temp));
121
                    pos += len - 1;
122
                }
123
                free(temp);
124
                ret = true;
125
            }
126
        }
127
        GlobalUnlock(h);
128
    }
129
    else
130
    {
131
        h = GetClipboardData(CF_TEXT);
132
133
        if (h)
134
        {
135
            const char *const data = static_cast<char*>(GlobalLock(h));
136
            if (data)
137
            {
138
                text.insert(pos, data);
139
                pos += strlen(data);
140
                ret = true;
141
            }
142
            GlobalUnlock(h);
143
        }
144
    }
145
146
    CloseClipboard();
147
    return ret;
148
}
149
150
bool sendBuffer(const std::string &restrict text)
151
{
152
    const int wCharsLen = MultiByteToWideChar(CP_UTF8,
153
        0, text.c_str(), -1, nullptr, 0);
154
    if (!wCharsLen)
155
        return false;
156
157
    HANDLE h = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
158
        CAST_SIZE(wCharsLen) * sizeof(WCHAR));
159
    WCHAR *const out = static_cast<WCHAR*>(GlobalLock(h));
160
161
    MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, out, wCharsLen);
162
163
    if (!OpenClipboard(nullptr))
164
    {
165
        GlobalUnlock(h);
166
        GlobalFree(h);
167
        return false;
168
    }
169
    GlobalUnlock(h);
170
    EmptyClipboard();
171
    if (!SetClipboardData(CF_UNICODETEXT, out))
172
    {
173
        GlobalFree(h);
174
        CloseClipboard();
175
        return false;
176
    }
177
    GlobalFree(h);
178
    CloseClipboard();
179
180
    return true;
181
}
182
183
#elif defined(__APPLE__)
184
185
// Sorry for the very long code, all nicer OS X APIs are coded in
186
// Objective C and not C!
187
// Also it does very thorough error handling
188
bool getDataFromPasteboard(PasteboardRef inPasteboard,
189
                           char* flavorText /* out */,
190
                           const int bufSize)
191
{
192
    ItemCount itemCount;
193
    PasteboardSyncFlags syncFlags = PasteboardSynchronize(inPasteboard);
194
    OSStatus err = PasteboardGetItemCount(inPasteboard, &itemCount);
195
    require_noerr(err, CantGetPasteboardItemCount);
196
197
    for (UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex ++)
198
    {
199
        PasteboardItemID    itemID;
200
        CFArrayRef          flavorTypeArray;
201
        CFIndex             flavorCount;
202
203
        err = PasteboardGetItemIdentifier(inPasteboard, itemIndex, &itemID);
204
        require_noerr(err, CantGetPasteboardItemIdentifier);
205
206
        err = PasteboardCopyItemFlavors(inPasteboard,
207
            itemID, &flavorTypeArray);
208
        require_noerr(err, CantCopyPasteboardItemFlavors);
209
210
        flavorCount = CFArrayGetCount(flavorTypeArray);
211
212
        for (CFIndex flavorIndex = 0; flavorIndex < flavorCount;
213
             flavorIndex ++)
214
        {
215
            CFStringRef flavorType = (CFStringRef)CFArrayGetValueAtIndex(
216
                flavorTypeArray, flavorIndex);
217
218
            // we're only interested by text...
219
            if (UTTypeConformsTo(flavorType, CFSTR("public.utf8-plain-text")))
220
            {
221
                CFDataRef flavorData;
222
                err = PasteboardCopyItemFlavorData(inPasteboard, itemID,
223
                                                   flavorType, &flavorData);
224
                require_noerr(err, CantCopyFlavorData);
225
                CFIndex flavorDataSize = CFDataGetLength(flavorData);
226
                flavorDataSize = (flavorDataSize<254) ? flavorDataSize : 254;
227
228
                if (flavorDataSize + 2 > bufSize)
229
                {
230
                    fprintf(stderr,
231
                        "Cannot copy clipboard, contents is too big!\n");
232
                    return false;
233
                }
234
235
                for (short dataIndex = 0; dataIndex <= flavorDataSize;
236
                     dataIndex ++)
237
                {
238
                    signed char byte = *(CFDataGetBytePtr(
239
                        flavorData) + dataIndex);
240
                    flavorText[dataIndex] = byte;
241
                }
242
243
                flavorText[flavorDataSize] = '\0';
244
                flavorText[flavorDataSize + 1] = '\n';
245
246
                CFRelease(flavorData);
247
                return true;
248
            }
249
250
            continue;
251
CantCopyFlavorData:
252
            fprintf(stderr, "Cannot copy clipboard, CantCopyFlavorData!\n");
253
        }
254
255
        CFRelease(flavorTypeArray);
256
        continue;
257
258
CantCopyPasteboardItemFlavors:
259
        fprintf(stderr,
260
            "Cannot copy clipboard, CantCopyPasteboardItemFlavors!\n");
261
        continue;
262
CantGetPasteboardItemIdentifier:
263
        fprintf(stderr,
264
            "Cannot copy clipboard, CantGetPasteboardItemIdentifier!\n");
265
        continue;
266
    }
267
    fprintf(stderr,
268
        "Cannot copy clipboard, found no acceptable flavour!\n");
269
    return false;
270
271
CantGetPasteboardItemCount:
272
    fprintf(stderr, "Cannot copy clipboard, CantGetPasteboardItemCount!\n");
273
    return false;
274
}
275
276
bool getClipBoard(char* text  /* out */, const int bufSize)
277
{
278
    PasteboardRef theClipboard;
279
    OSStatus err = PasteboardCreate(kPasteboardClipboard, &theClipboard);
280
    require_noerr(err, PasteboardCreateFailed);
281
282
    if (!getDataFromPasteboard(theClipboard, text, bufSize))
283
    {
284
        fprintf(stderr,
285
            "Cannot copy clipboard, getDataFromPasteboardFailed!\n");
286
        return false;
287
    }
288
289
    CFRelease(theClipboard);
290
291
    return true;
292
293
    // ---- error handling
294
PasteboardCreateFailed:
295
    fprintf(stderr, "Cannot copy clipboard, PasteboardCreateFailed!\n");
296
    CFRelease(theClipboard);
297
    return false;
298
}
299
300
bool retrieveBuffer(std::string& text, size_t& pos)
301
{
302
    const int bufSize = 512;
303
    char buffer[bufSize + 1];
304
305
    if (getClipBoard(buffer, bufSize))
306
    {
307
        text = buffer;
308
        pos += strlen(buffer);
309
        return true;
310
    }
311
    else
312
    {
313
        return false;
314
    }
315
}
316
317
bool sendBuffer(const std::string &restrict text)
318
{
319
    return false;
320
}
321
322
#elif defined USE_X11
323
324
static char* getSelection2(Display *const dpy, Window us, Atom selection,
325
                           Atom request_target)
326
{
327
    int max_events = 50;
328
    Window owner = XGetSelectionOwner(dpy, selection);
329
330
    if (owner == None)
331
        return nullptr;
332
333
    XConvertSelection(dpy, selection, request_target,
334
        XA_PRIMARY, us, CurrentTime);
335
    XFlush(dpy);
336
337
    while (max_events --)
338
    {
339
        XEvent e;
340
341
        XNextEvent(dpy, &e);
342
        if (e.type == SelectionNotify)
343
        {
344
            if (e.xselection.property == None)
345
                return nullptr;
346
347
            long unsigned len, left, dummy;
348
            int format;
349
            Atom type;
350
            unsigned char *data = nullptr;
351
352
            int ret = XGetWindowProperty(dpy, us, e.xselection.property, 0, 0,
353
                False, AnyPropertyType, &type, &format, &len, &left, &data);
354
            if (left < 1)
355
            {
356
                if (ret == Success)
357
                    XFree(data);
358
                return nullptr;
359
            }
360
361
            ret = XGetWindowProperty(dpy, us, e.xselection.property, 0,
362
                left, False, AnyPropertyType, &type, &format, &len,
363
                &dummy, &data);
364
365
            if (ret != Success)
366
                return nullptr;
367
368
            return reinterpret_cast<char*>(data);
369
        }
370
    }
371
    return nullptr;
372
}
373
374
static Atom requestAtom;
375
376
static char* getSelection(Display *const dpy, Window us, Atom selection)
377
{
378
    char *data = nullptr;
379
    if (requestAtom != None)
380
        data = getSelection2(dpy, us, selection, requestAtom);
381
    if (!data)
382
        data = getSelection2(dpy, us, selection, XA_STRING);
383
    return data;
384
}
385
386
bool retrieveBuffer(std::string& text, size_t& pos)
387
{
388
    SDL_SysWMinfo info;
389
390
    SDL_VERSION(&info.version);
391
    if (SDL::getWindowWMInfo(mainGraphics->getWindow(), &info))
392
    {
393
        Display *const dpy = info.info.x11.display;
394
        Window us = info.info.x11.window;
395
396
        requestAtom = XInternAtom(dpy, "UTF8_STRING", true);
397
        char *data = getSelection(dpy, us, XA_PRIMARY);
398
        if (!data)
399
            data = getSelection(dpy, us, XA_SECONDARY);
400
        if (!data)
401
        {
402
            Atom XA_CLIPBOARD = XInternAtom(dpy, "CLIPBOARD", 0);
403
            if (XA_CLIPBOARD != None)
404
                data = getSelection(dpy, us, XA_CLIPBOARD);
405
        }
406
407
        if (data)
408
        {
409
            // check cursor position
410
            const size_t sz = text.size();
411
            if (pos > sz)
412
                pos = sz;
413
414
            text.insert(pos, data);
415
            pos += strlen(data);
416
            XFree(data);
417
418
            return true;
419
        }
420
    }
421
    return false;
422
}
423
424
static bool runxsel(const std::string &text, const char *p1,
425
                    const char *p2 = nullptr);
426
427
bool sendBuffer(const std::string &restrict text)
428
{
429
    runxsel(text, "-i");
430
    runxsel(text, "-b", "-i");
431
    return true;
432
}
433
434
static bool runxsel(const std::string &text, const char *p1, const char *p2)
435
{
436
    pid_t pid;
437
    int fd[2];
438
439
    if (pipe(fd))
440
        return false;
441
442
    if ((pid = fork()) == -1)
443
    {   // fork error
444
        return false;
445
    }
446
    else if (!pid)
447
    {   // child
448
        close(fd[1]);
449
450
        if (fd[0] != STDIN_FILENO)
451
        {
452
            if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
453
            {
454
                close(fd[0]);
455
                _exit(1);
456
            }
457
            close(fd[0]);
458
        }
459
460
        const char *const xselPath =
461
#if defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
462
            "/usr/local/bin/xsel";
463
#else  // defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
464
            "/usr/bin/xsel";
465
#endif  // defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
466
467
        if (p2)
468
        {
469
            execl(xselPath, "xsel", p1, p2,
470
                static_cast<char *>(nullptr));
471
        }
472
        else
473
        {
474
            execl(xselPath, "xsel", p1,
475
                static_cast<char *>(nullptr));
476
        }
477
478
        _exit(1);
479
    }
480
481
    // parent
482
    close(fd[0]);
483
    const size_t len = text.length();
484
    if (write(fd[1], text.c_str(), len) != static_cast<ssize_t>(len))
485
    {
486
        close(fd[1]);
487
        return false;
488
    }
489
    close(fd[1]);
490
    return true;
491
}
492
493
#elif defined __native_client__
494
495
bool retrieveBuffer(std::string& text, size_t& pos)
496
{
497
    NaclMessageHandle *handle = naclRegisterMessageHandler("clipboard-paste");
498
    naclPostMessage("clipboard-paste", "");
499
    std::string response = naclWaitForMessage(handle);
500
    text.insert(pos, response);
501
    pos += response.size();
502
    return true;
503
}
504
505
bool sendBuffer(const std::string &restrict text)
506
{
507
    naclPostMessage("clipboard-copy", text);
508
    return true;
509
}
510
#else  // WIN32
511
512
bool retrieveBuffer(std::string &text A_UNUSED, size_t &pos A_UNUSED)
513
{
514
    return false;
515
}
516
517
bool sendBuffer(const std::string &restrict text A_UNUSED)
518
{
519
    return false;
520
}
521
#endif  // WIN32
522
#endif  // USE_SDL2