checkpoint. adding support for unicode in clipboard.
This commit is contained in:
parent
4c2cbb9f03
commit
643d0f1089
|
@ -0,0 +1,530 @@
|
||||||
|
#include "CUnicode.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// local utility functions
|
||||||
|
//
|
||||||
|
|
||||||
|
inline
|
||||||
|
static
|
||||||
|
UInt16
|
||||||
|
decode16(const UInt8* n)
|
||||||
|
{
|
||||||
|
union x16 {
|
||||||
|
UInt8 n8[2];
|
||||||
|
UInt16 n16;
|
||||||
|
} c;
|
||||||
|
c.n8[0] = n[0];
|
||||||
|
c.n8[1] = n[1];
|
||||||
|
return c.n16;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
static
|
||||||
|
UInt32
|
||||||
|
decode32(const UInt8* n)
|
||||||
|
{
|
||||||
|
union x32 {
|
||||||
|
UInt8 n8[4];
|
||||||
|
UInt32 n32;
|
||||||
|
} c;
|
||||||
|
c.n8[0] = n[0];
|
||||||
|
c.n8[1] = n[1];
|
||||||
|
c.n8[2] = n[2];
|
||||||
|
c.n8[3] = n[3];
|
||||||
|
return c.n32;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// CUnicode
|
||||||
|
//
|
||||||
|
|
||||||
|
UInt32 CUnicode::s_invalid = 0x0000ffff;
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UTF8ToUCS2(const CString& src)
|
||||||
|
{
|
||||||
|
// get size of input string and reserve some space in output.
|
||||||
|
// include UTF8's nul terminator.
|
||||||
|
UInt32 n = src.size() + 1;
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(2 * n);
|
||||||
|
|
||||||
|
// convert each character
|
||||||
|
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
|
||||||
|
while (n > 0) {
|
||||||
|
UInt32 c = fromUTF8(data, n);
|
||||||
|
if (c != s_invalid && c < 0x0000ffff) {
|
||||||
|
UInt16 ucs2 = static_cast<UInt16>(c);
|
||||||
|
dst.append(reinterpret_cast<const char*>(&ucs2), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UTF8ToUCS4(const CString& src)
|
||||||
|
{
|
||||||
|
// get size of input string and reserve some space in output.
|
||||||
|
// include UTF8's nul terminator.
|
||||||
|
UInt32 n = src.size() + 1;
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(4 * n);
|
||||||
|
|
||||||
|
// convert each character
|
||||||
|
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
|
||||||
|
while (n > 0) {
|
||||||
|
UInt32 c = fromUTF8(data, n);
|
||||||
|
if (c != s_invalid) {
|
||||||
|
dst.append(reinterpret_cast<const char*>(&c), 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UTF8ToUTF16(const CString& src)
|
||||||
|
{
|
||||||
|
// get size of input string and reserve some space in output.
|
||||||
|
// include UTF8's nul terminator.
|
||||||
|
UInt32 n = src.size() + 1;
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(2 * n);
|
||||||
|
|
||||||
|
// convert each character
|
||||||
|
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
|
||||||
|
while (n > 0) {
|
||||||
|
UInt32 c = fromUTF8(data, n);
|
||||||
|
if (c != s_invalid && c < 0x0010ffff) {
|
||||||
|
if (c < 0x00010000) {
|
||||||
|
UInt16 ucs2 = static_cast<UInt16>(c);
|
||||||
|
dst.append(reinterpret_cast<const char*>(&ucs2), 2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c -= 0x00010000;
|
||||||
|
UInt16 utf16h = static_cast<UInt16>(c >> 10) + 0xd800;
|
||||||
|
UInt16 utf16l = (static_cast<UInt16>(c) & 0x03ff) + 0xdc00;
|
||||||
|
dst.append(reinterpret_cast<const char*>(&utf16h), 2);
|
||||||
|
dst.append(reinterpret_cast<const char*>(&utf16l), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UTF8ToUTF32(const CString& src)
|
||||||
|
{
|
||||||
|
// FIXME -- should ensure dst has no characters over U-0010FFFF
|
||||||
|
return UTF8ToUCS4(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UCS2ToUTF8(const CString& src)
|
||||||
|
{
|
||||||
|
UInt32 n = src.size() >> 1;
|
||||||
|
return doUCS2ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UCS4ToUTF8(const CString& src)
|
||||||
|
{
|
||||||
|
UInt32 n = src.size() >> 2;
|
||||||
|
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UTF16ToUTF8(const CString& src)
|
||||||
|
{
|
||||||
|
UInt32 n = src.size() >> 1;
|
||||||
|
return doUTF16ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UTF32ToUTF8(const CString& src)
|
||||||
|
{
|
||||||
|
UInt32 n = src.size() >> 2;
|
||||||
|
return doUTF32ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::UTF8ToText(const CString& src)
|
||||||
|
{
|
||||||
|
// convert to wide char
|
||||||
|
wchar_t* tmp = UTF8ToWideChar(src);
|
||||||
|
|
||||||
|
// get length of multibyte string
|
||||||
|
mbstate_t state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
const wchar_t* scratch = tmp;
|
||||||
|
size_t len = wcsrtombs(NULL, &scratch, 0, &state);
|
||||||
|
if (len == (size_t)-1) {
|
||||||
|
// invalid character in src
|
||||||
|
delete[] tmp;
|
||||||
|
return CString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to multibyte
|
||||||
|
scratch = tmp;
|
||||||
|
char* dst = new char[len + 1];
|
||||||
|
wcsrtombs(dst, &scratch, len + 1, &state);
|
||||||
|
CString text(dst);
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
delete[] dst;
|
||||||
|
delete[] tmp;
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::textToUTF8(const CString& src)
|
||||||
|
{
|
||||||
|
// get length of wide char string
|
||||||
|
mbstate_t state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
const char* scratch = src.c_str();
|
||||||
|
size_t len = mbsrtowcs(NULL, &scratch, 0, &state);
|
||||||
|
if (len == (size_t)-1) {
|
||||||
|
// invalid character in src
|
||||||
|
return CString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert multibyte to wide char
|
||||||
|
scratch = src.c_str();
|
||||||
|
wchar_t* dst = new wchar_t[len + 1];
|
||||||
|
mbsrtowcs(dst, &scratch, len + 1, &state);
|
||||||
|
|
||||||
|
// convert to UTF8
|
||||||
|
CString utf8 = wideCharToUTF8(dst);
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
delete[] dst;
|
||||||
|
|
||||||
|
return utf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t*
|
||||||
|
CUnicode::UTF8ToWideChar(const CString& src)
|
||||||
|
{
|
||||||
|
// convert to platform's wide character encoding.
|
||||||
|
// note -- this must include a wide nul character (independent of
|
||||||
|
// the CString's nul character).
|
||||||
|
#if WINDOWS_LIKE
|
||||||
|
CString tmp = UTF8ToUCS16(src);
|
||||||
|
UInt32 size = tmp.size() >> 1;
|
||||||
|
#elif UNIX_LIKE
|
||||||
|
CString tmp = UTF8ToUCS4(src);
|
||||||
|
UInt32 size = tmp.size() >> 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// copy to a wchar_t array
|
||||||
|
wchar_t* dst = new wchar_t[size];
|
||||||
|
::memcpy(dst, src.data(), sizeof(wchar_t) * size);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::wideCharToUTF8(const wchar_t* src)
|
||||||
|
{
|
||||||
|
// convert from platform's wide character encoding.
|
||||||
|
// note -- this must include a wide nul character (independent of
|
||||||
|
// the CString's nul character).
|
||||||
|
#if WINDOWS_LIKE
|
||||||
|
return doUCS16ToUTF8(reinterpret_cast<const UInt8*>(src), wcslen(src));
|
||||||
|
#elif UNIX_LIKE
|
||||||
|
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src), wcslen(src));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::doUCS2ToUTF8(const UInt8* data, UInt32 n)
|
||||||
|
{
|
||||||
|
// make some space
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(n);
|
||||||
|
|
||||||
|
// convert each character
|
||||||
|
for (; n > 0; data += 2, --n) {
|
||||||
|
UInt32 c = decode16(data);
|
||||||
|
toUTF8(dst, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove extra trailing nul
|
||||||
|
if (dst.size() > 0 && dst[dst.size() - 1] == '\0') {
|
||||||
|
dst.resize(dst.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::doUCS4ToUTF8(const UInt8* data, UInt32 n)
|
||||||
|
{
|
||||||
|
// make some space
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(n);
|
||||||
|
|
||||||
|
// convert each character
|
||||||
|
for (; n > 0; data += 4, --n) {
|
||||||
|
UInt32 c = decode32(data);
|
||||||
|
toUTF8(dst, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove extra trailing nul
|
||||||
|
if (dst.size() > 0 && dst[dst.size() - 1] == '\0') {
|
||||||
|
dst.resize(dst.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::doUTF16ToUTF8(const UInt8* data, UInt32 n)
|
||||||
|
{
|
||||||
|
// make some space
|
||||||
|
CString dst;
|
||||||
|
dst.reserve(n);
|
||||||
|
|
||||||
|
// convert each character
|
||||||
|
for (; n > 0; data += 2, --n) {
|
||||||
|
UInt32 c = decode16(data);
|
||||||
|
if (c < 0x0000d800 || c > 0x0000dfff) {
|
||||||
|
toUTF8(dst, c);
|
||||||
|
}
|
||||||
|
else if (n == 1) {
|
||||||
|
// error -- missing second word
|
||||||
|
}
|
||||||
|
else if (c >= 0x0000d800 && c <= 0x0000dbff) {
|
||||||
|
UInt32 c2 = decode16(data);
|
||||||
|
data += 2;
|
||||||
|
--n;
|
||||||
|
if (c2 < 0x0000dc00 || c2 > 0x0000dfff) {
|
||||||
|
// error -- [d800,dbff] not followed by [dc00,dfff]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c = (((c - 0x0000d800) << 10) | (c2 - 0x0000dc00)) + 0x00010000;
|
||||||
|
toUTF8(dst, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// error -- [dc00,dfff] without leading [d800,dbff]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove extra trailing nul
|
||||||
|
if (dst.size() > 0 && dst[dst.size() - 1] == '\0') {
|
||||||
|
dst.resize(dst.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CUnicode::doUTF32ToUTF8(const UInt8* data, UInt32 n)
|
||||||
|
{
|
||||||
|
// FIXME -- should check that src has no characters over U-0010FFFF
|
||||||
|
return doUCS4ToUTF8(data, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt32
|
||||||
|
CUnicode::fromUTF8(const UInt8*& data, UInt32& n)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(n != 0);
|
||||||
|
|
||||||
|
// compute character encoding length, checking for overlong
|
||||||
|
// sequences (i.e. characters that don't use the shortest
|
||||||
|
// possible encoding).
|
||||||
|
UInt32 size;
|
||||||
|
if (data[0] < 0x80) {
|
||||||
|
// 0xxxxxxx
|
||||||
|
size = 1;
|
||||||
|
}
|
||||||
|
else if (data[0] < 0xc0) {
|
||||||
|
// 10xxxxxx -- in the middle of a multibyte character. skip
|
||||||
|
// until we find a start byte and return error.
|
||||||
|
do {
|
||||||
|
--n;
|
||||||
|
++data;
|
||||||
|
} while (n > 0 && (data[0] & 0xc0) == 0x80);
|
||||||
|
return s_invalid;
|
||||||
|
}
|
||||||
|
else if (data[0] < 0xe0) {
|
||||||
|
// 110xxxxx
|
||||||
|
size = 2;
|
||||||
|
}
|
||||||
|
else if (data[0] < 0xf0) {
|
||||||
|
// 1110xxxx
|
||||||
|
size = 3;
|
||||||
|
}
|
||||||
|
else if (data[0] < 0xf8) {
|
||||||
|
// 11110xxx
|
||||||
|
size = 4;
|
||||||
|
}
|
||||||
|
else if (data[0] < 0xfc) {
|
||||||
|
// 111110xx
|
||||||
|
size = 5;
|
||||||
|
}
|
||||||
|
else if (data[0] < 0xfe) {
|
||||||
|
// 1111110x
|
||||||
|
size = 6;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// invalid sequence. dunno how many bytes to skip so skip one.
|
||||||
|
--n;
|
||||||
|
++data;
|
||||||
|
return s_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we have enough data
|
||||||
|
if (size > n) {
|
||||||
|
data += n;
|
||||||
|
n = 0;
|
||||||
|
return s_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract character
|
||||||
|
UInt32 c;
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
c = static_cast<UInt32>(data[0]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
c = ((static_cast<UInt32>(data[0]) & 0x1f) << 6) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
c = ((static_cast<UInt32>(data[0]) & 0x0f) << 12) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
|
||||||
|
((static_cast<UInt32>(data[2]) & 0x3f) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
c = ((static_cast<UInt32>(data[0]) & 0x07) << 18) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
c = ((static_cast<UInt32>(data[0]) & 0x03) << 24) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 18) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
c = ((static_cast<UInt32>(data[0]) & 0x01) << 30) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 24) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 18) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
|
||||||
|
((static_cast<UInt32>(data[1]) & 0x3f) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0 && "invalid size");
|
||||||
|
}
|
||||||
|
|
||||||
|
// update parameters
|
||||||
|
data += size;
|
||||||
|
n -= size;
|
||||||
|
|
||||||
|
// check for characters that didn't use the smallest possible encoding
|
||||||
|
static UInt32 s_minChar[] = {
|
||||||
|
0,
|
||||||
|
0x00000000,
|
||||||
|
0x00000080,
|
||||||
|
0x00000800,
|
||||||
|
0x00010000,
|
||||||
|
0x00200000,
|
||||||
|
0x04000000
|
||||||
|
};
|
||||||
|
if (c < s_minChar[size]) {
|
||||||
|
return s_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that all bytes after the first have the pattern 10xxxxxx.
|
||||||
|
UInt8 a = 0x80;
|
||||||
|
switch (size) {
|
||||||
|
case 6:
|
||||||
|
a |= data[5];
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
a |= data[4];
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
a |= data[3];
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
a |= data[2];
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
a |= data[1];
|
||||||
|
}
|
||||||
|
if ((a & 0xc0) != 0x80) {
|
||||||
|
return s_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CUnicode::toUTF8(CString& dst, const UInt32 c)
|
||||||
|
{
|
||||||
|
UInt8 data[6];
|
||||||
|
|
||||||
|
if (c < 0x00000080) {
|
||||||
|
data[0] = static_cast<UInt8>(c);
|
||||||
|
dst.append(reinterpret_cast<char*>(data), 1);
|
||||||
|
}
|
||||||
|
else if (c < 0x00000800) {
|
||||||
|
data[0] = static_cast<UInt8>((c >> 6) & 0x0000001f) + 0xc0;
|
||||||
|
data[1] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
||||||
|
dst.append(reinterpret_cast<char*>(data), 2);
|
||||||
|
}
|
||||||
|
else if (c < 0x00010000) {
|
||||||
|
data[0] = static_cast<UInt8>((c >> 12) & 0x0000000f) + 0xe0;
|
||||||
|
data[1] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
||||||
|
data[2] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
||||||
|
dst.append(reinterpret_cast<char*>(data), 3);
|
||||||
|
}
|
||||||
|
else if (c < 0x00200000) {
|
||||||
|
data[0] = static_cast<UInt8>((c >> 18) & 0x00000007) + 0xf0;
|
||||||
|
data[1] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
|
||||||
|
data[2] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
||||||
|
data[3] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
||||||
|
dst.append(reinterpret_cast<char*>(data), 4);
|
||||||
|
}
|
||||||
|
else if (c < 0x04000000) {
|
||||||
|
data[0] = static_cast<UInt8>((c >> 24) & 0x00000003) + 0xf8;
|
||||||
|
data[1] = static_cast<UInt8>((c >> 18) & 0x0000003f) + 0x80;
|
||||||
|
data[2] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
|
||||||
|
data[3] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
||||||
|
data[4] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
||||||
|
dst.append(reinterpret_cast<char*>(data), 5);
|
||||||
|
}
|
||||||
|
else if (c < 0x80000000) {
|
||||||
|
data[0] = static_cast<UInt8>((c >> 30) & 0x00000001) + 0xfc;
|
||||||
|
data[1] = static_cast<UInt8>((c >> 24) & 0x0000003f) + 0x80;
|
||||||
|
data[2] = static_cast<UInt8>((c >> 18) & 0x0000003f) + 0x80;
|
||||||
|
data[3] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
|
||||||
|
data[4] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
|
||||||
|
data[5] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
|
||||||
|
dst.append(reinterpret_cast<char*>(data), 6);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// invalid character
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef CUNICODE_H
|
||||||
|
#define CUNICODE_H
|
||||||
|
|
||||||
|
#include "CString.h"
|
||||||
|
#include "BasicTypes.h"
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
class CUnicode {
|
||||||
|
public:
|
||||||
|
static CString UTF8ToUCS2(const CString&);
|
||||||
|
static CString UTF8ToUCS4(const CString&);
|
||||||
|
static CString UTF8ToUTF16(const CString&);
|
||||||
|
static CString UTF8ToUTF32(const CString&);
|
||||||
|
|
||||||
|
static CString UCS2ToUTF8(const CString&);
|
||||||
|
static CString UCS4ToUTF8(const CString&);
|
||||||
|
static CString UTF16ToUTF8(const CString&);
|
||||||
|
static CString UTF32ToUTF8(const CString&);
|
||||||
|
|
||||||
|
// convert UTF-8 to/from the current locale's encoding
|
||||||
|
static CString UTF8ToText(const CString&);
|
||||||
|
static CString textToUTF8(const CString&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// convert UTF8 to nul terminated wchar_t string (using whatever
|
||||||
|
// encoding is native to the platform). caller must delete[]
|
||||||
|
// the returned string.
|
||||||
|
static wchar_t* UTF8ToWideChar(const CString&);
|
||||||
|
|
||||||
|
// convert nul terminated wchar_t string (in platform's native
|
||||||
|
// encoding) to UTF8.
|
||||||
|
static CString wideCharToUTF8(const wchar_t*);
|
||||||
|
|
||||||
|
// internal conversion to UTF8
|
||||||
|
static CString doUCS2ToUTF8(const UInt8* src, UInt32 n);
|
||||||
|
static CString doUCS4ToUTF8(const UInt8* src, UInt32 n);
|
||||||
|
static CString doUTF16ToUTF8(const UInt8* src, UInt32 n);
|
||||||
|
static CString doUTF32ToUTF8(const UInt8* src, UInt32 n);
|
||||||
|
|
||||||
|
// convert characters to/from UTF8
|
||||||
|
static UInt32 fromUTF8(const UInt8*& src, UInt32& size);
|
||||||
|
static void toUTF8(CString& dst, const UInt32 c);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static UInt32 s_invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -8,12 +8,14 @@ libbase_a_SOURCES = \
|
||||||
CLog.cpp \
|
CLog.cpp \
|
||||||
CStopwatch.cpp \
|
CStopwatch.cpp \
|
||||||
CString.cpp \
|
CString.cpp \
|
||||||
|
CUnicode.cpp \
|
||||||
XBase.cpp \
|
XBase.cpp \
|
||||||
BasicTypes.h \
|
BasicTypes.h \
|
||||||
CFunctionJob.h \
|
CFunctionJob.h \
|
||||||
CLog.h \
|
CLog.h \
|
||||||
CStopwatch.h \
|
CStopwatch.h \
|
||||||
CString.h \
|
CString.h \
|
||||||
|
CUnicode.h \
|
||||||
IInterface.h \
|
IInterface.h \
|
||||||
IJob.h \
|
IJob.h \
|
||||||
TMethodJob.h \
|
TMethodJob.h \
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
#include "CXWindowsClipboard.h"
|
#include "CXWindowsClipboard.h"
|
||||||
|
#include "CXWindowsClipboardTextConverter.h"
|
||||||
|
#include "CXWindowsClipboardUCS2Converter.h"
|
||||||
|
#include "CXWindowsClipboardUTF8Converter.h"
|
||||||
#include "CXWindowsUtil.h"
|
#include "CXWindowsUtil.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
@ -52,6 +55,20 @@ CXWindowsClipboard::CXWindowsClipboard(Display* display,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add converters
|
||||||
|
m_converters.push_back(new CXWindowsClipboardUTF8Converter(m_display,
|
||||||
|
"text/plain;charset=UTF-8"));
|
||||||
|
m_converters.push_back(new CXWindowsClipboardUTF8Converter(m_display,
|
||||||
|
"UTF8_STRING"));
|
||||||
|
m_converters.push_back(new CXWindowsClipboardUCS2Converter(m_display,
|
||||||
|
"text/plain;charset=ISO-10646-UCS-2"));
|
||||||
|
m_converters.push_back(new CXWindowsClipboardUCS2Converter(m_display,
|
||||||
|
"text/unicode"));
|
||||||
|
m_converters.push_back(new CXWindowsClipboardTextConverter(m_display,
|
||||||
|
"text/plain"));
|
||||||
|
m_converters.push_back(new CXWindowsClipboardTextConverter(m_display,
|
||||||
|
"STRING"));
|
||||||
|
|
||||||
// we have no data
|
// we have no data
|
||||||
clearCache();
|
clearCache();
|
||||||
}
|
}
|
||||||
|
@ -59,6 +76,7 @@ CXWindowsClipboard::CXWindowsClipboard(Display* display,
|
||||||
CXWindowsClipboard::~CXWindowsClipboard()
|
CXWindowsClipboard::~CXWindowsClipboard()
|
||||||
{
|
{
|
||||||
clearReplies();
|
clearReplies();
|
||||||
|
clearConverters();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -124,7 +142,7 @@ CXWindowsClipboard::addSimpleRequest(Window requestor,
|
||||||
|
|
||||||
// handle targets
|
// handle targets
|
||||||
CString data;
|
CString data;
|
||||||
Atom type = None;
|
Atom type = None;
|
||||||
int format = 0;
|
int format = 0;
|
||||||
if (target == m_atomTargets) {
|
if (target == m_atomTargets) {
|
||||||
type = getTargetsData(data, &format);
|
type = getTargetsData(data, &format);
|
||||||
|
@ -132,9 +150,17 @@ CXWindowsClipboard::addSimpleRequest(Window requestor,
|
||||||
else if (target == m_atomTimestamp) {
|
else if (target == m_atomTimestamp) {
|
||||||
type = getTimestampData(data, &format);
|
type = getTimestampData(data, &format);
|
||||||
}
|
}
|
||||||
else if (target == m_atomString ||
|
else {
|
||||||
target == m_atomText) {
|
IXWindowsClipboardConverter* converter = getConverter(target);
|
||||||
type = getStringData(data, &format);
|
IClipboard::EFormat clipboardFormat = converter->getFormat();
|
||||||
|
if (!m_added[clipboardFormat]) {
|
||||||
|
type = None;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
type = converter->getAtom();
|
||||||
|
format = converter->getDataSize();
|
||||||
|
data = converter->fromIClipboard(m_data[clipboardFormat]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != None) {
|
if (type != None) {
|
||||||
|
@ -334,17 +360,41 @@ CXWindowsClipboard::get(EFormat format) const
|
||||||
return m_data[format];
|
return m_data[format];
|
||||||
}
|
}
|
||||||
|
|
||||||
IClipboard::EFormat
|
void
|
||||||
CXWindowsClipboard::getFormat(Atom src) const
|
CXWindowsClipboard::clearConverters()
|
||||||
{
|
{
|
||||||
// FIXME -- handle more formats (especially mime-type-like formats
|
for (ConverterList::iterator index = m_converters.begin();
|
||||||
// and various character encodings like unicode).
|
index != m_converters.end(); ++index) {
|
||||||
if (src == m_atomString ||
|
delete *index;
|
||||||
src == m_atomText /*||
|
|
||||||
src == m_atomCompoundText*/) {
|
|
||||||
return IClipboard::kText;
|
|
||||||
}
|
}
|
||||||
return IClipboard::kNumFormats;
|
m_converters.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
IXWindowsClipboardConverter*
|
||||||
|
CXWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const
|
||||||
|
{
|
||||||
|
IXWindowsClipboardConverter* converter = NULL;
|
||||||
|
for (ConverterList::const_iterator index = m_converters.begin();
|
||||||
|
index != m_converters.end(); ++index) {
|
||||||
|
converter = *index;
|
||||||
|
if (converter->getAtom() == target) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (converter == NULL) {
|
||||||
|
log((CLOG_DEBUG1 " no converter for target %d", target));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// optionally skip already handled targets
|
||||||
|
if (onlyIfNotAdded) {
|
||||||
|
if (m_added[converter->getFormat()]) {
|
||||||
|
log((CLOG_DEBUG1 " skipping handled format %d", converter->getFormat()));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -438,44 +488,29 @@ CXWindowsClipboard::icccmFillCache()
|
||||||
const Atom* targets = reinterpret_cast<const Atom*>(data.data());
|
const Atom* targets = reinterpret_cast<const Atom*>(data.data());
|
||||||
const UInt32 numTargets = data.size() / sizeof(Atom);
|
const UInt32 numTargets = data.size() / sizeof(Atom);
|
||||||
for (UInt32 i = 0; i < numTargets; ++i) {
|
for (UInt32 i = 0; i < numTargets; ++i) {
|
||||||
// determine the expected clipboard format
|
// see if we have a converter for this target
|
||||||
Atom target = targets[i];
|
Atom target = targets[i];
|
||||||
IClipboard::EFormat expectedFormat = getFormat(target);
|
IXWindowsClipboardConverter* converter = getConverter(target, true);
|
||||||
if (expectedFormat == IClipboard::kNumFormats) {
|
if (converter == NULL) {
|
||||||
log((CLOG_DEBUG1 " no format for target %d", target));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
log((CLOG_DEBUG1 " source target %d -> %d", target, expectedFormat));
|
|
||||||
|
|
||||||
// skip already handled targets
|
|
||||||
if (m_added[expectedFormat]) {
|
|
||||||
log((CLOG_DEBUG1 " skipping handled format %d", expectedFormat));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the data
|
||||||
Atom actualTarget;
|
Atom actualTarget;
|
||||||
CString targetData;
|
CString targetData;
|
||||||
if (!icccmGetSelection(target, &actualTarget, &targetData)) {
|
if (!icccmGetSelection(target, &actualTarget, &targetData)) {
|
||||||
log((CLOG_DEBUG1 " no data for target", target));
|
log((CLOG_DEBUG1 " no data for target", target));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
logc(actualTarget != target, (CLOG_DEBUG1 " actual target is %d", actualTarget));
|
if (actualTarget != target) {
|
||||||
|
log((CLOG_DEBUG1 " expected (%d) and actual (%d) targets differ", target, actualTarget));
|
||||||
// use the actual format, not the expected
|
|
||||||
IClipboard::EFormat actualFormat = getFormat(actualTarget);
|
|
||||||
if (actualFormat == IClipboard::kNumFormats) {
|
|
||||||
log((CLOG_DEBUG1 " no format for target %d", actualTarget));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (m_added[actualFormat]) {
|
|
||||||
log((CLOG_DEBUG1 " skipping handled format %d", actualFormat));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add to clipboard and note we've done it
|
// add to clipboard and note we've done it
|
||||||
m_data[actualFormat] = targetData;
|
m_data[converter->getFormat()] = converter->toIClipboard(targetData);
|
||||||
m_added[actualFormat] = true;
|
m_added[converter->getFormat()] = true;
|
||||||
log((CLOG_DEBUG " added format %d for target %d", actualFormat, target));
|
log((CLOG_DEBUG " added format %d for target %d", converter->getFormat(), target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,42 +711,36 @@ CXWindowsClipboard::motifFillCache()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine the expected clipboard format
|
|
||||||
Atom target = motifFormat->m_type;
|
|
||||||
IClipboard::EFormat expectedFormat = getFormat(target);
|
|
||||||
if (expectedFormat == IClipboard::kNumFormats) {
|
|
||||||
log((CLOG_DEBUG1 " no format for target %d", target));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
log((CLOG_DEBUG1 " source target %d -> %d", target, expectedFormat));
|
|
||||||
|
|
||||||
// skip already handled targets
|
// see if we have a converter for this target
|
||||||
if (m_added[expectedFormat]) {
|
Atom target = motifFormat->m_type;
|
||||||
log((CLOG_DEBUG1 " skipping handled format %d", expectedFormat));
|
IXWindowsClipboardConverter* converter = getConverter(target, true);
|
||||||
|
if (converter == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the data (finally)
|
// get the data (finally)
|
||||||
SInt32 length = motifFormat->m_length;
|
SInt32 length = motifFormat->m_length;
|
||||||
sprintf(name, "_MOTIF_CLIP_ITEM_%d", motifFormat->m_data);
|
sprintf(name, "_MOTIF_CLIP_ITEM_%d", motifFormat->m_data);
|
||||||
Atom atomData = XInternAtom(m_display, name, False);
|
Atom atomData = XInternAtom(m_display, name, False), atomTarget;
|
||||||
data = "";
|
CString targetData;
|
||||||
if (!CXWindowsUtil::getWindowProperty(m_display, root,
|
if (!CXWindowsUtil::getWindowProperty(m_display, root,
|
||||||
atomData, &data,
|
atomData, &targetData,
|
||||||
&target, &format, False)) {
|
&atomTarget, &format, False)) {
|
||||||
|
log((CLOG_DEBUG1 " no data for target", target));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (target != atomData) {
|
if (atomTarget != atomData) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// truncate data to length specified in the format
|
// truncate data to length specified in the format
|
||||||
data.erase(length);
|
targetData.erase(length);
|
||||||
|
|
||||||
// add to clipboard and note we've done it
|
// add to clipboard and note we've done it
|
||||||
m_data[expectedFormat] = data;
|
m_data[converter->getFormat()] = converter->toIClipboard(targetData);
|
||||||
m_added[expectedFormat] = true;
|
m_added[converter->getFormat()] = true;
|
||||||
log((CLOG_DEBUG " added format %d for target %d", expectedFormat, motifFormat->m_type));
|
log((CLOG_DEBUG " added format %d for target %d", converter->getFormat(), target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,7 +1090,7 @@ CXWindowsClipboard::getTargetsData(CString& data, int* format) const
|
||||||
{
|
{
|
||||||
assert(format != NULL);
|
assert(format != NULL);
|
||||||
|
|
||||||
// construct response
|
// add standard targets
|
||||||
Atom atom;
|
Atom atom;
|
||||||
atom = m_atomTargets;
|
atom = m_atomTargets;
|
||||||
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
||||||
|
@ -1069,11 +1098,17 @@ CXWindowsClipboard::getTargetsData(CString& data, int* format) const
|
||||||
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
||||||
atom = m_atomTimestamp;
|
atom = m_atomTimestamp;
|
||||||
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
||||||
if (m_added[kText]) {
|
|
||||||
atom = m_atomString;
|
// add targets we can convert to
|
||||||
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
for (ConverterList::const_iterator index = m_converters.begin();
|
||||||
atom = m_atomText;
|
index != m_converters.end(); ++index) {
|
||||||
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
IXWindowsClipboardConverter* converter = *index;
|
||||||
|
|
||||||
|
// skip formats we don't have
|
||||||
|
if (!m_added[converter->getFormat()]) {
|
||||||
|
atom = converter->getAtom();
|
||||||
|
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*format = 32;
|
*format = 32;
|
||||||
|
@ -1092,21 +1127,6 @@ CXWindowsClipboard::getTimestampData(CString& data, int* format) const
|
||||||
return m_atomTimestamp;
|
return m_atomTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom
|
|
||||||
CXWindowsClipboard::getStringData(CString& data, int* format) const
|
|
||||||
{
|
|
||||||
assert(format != NULL);
|
|
||||||
|
|
||||||
if (m_added[kText]) {
|
|
||||||
data = m_data[kText];
|
|
||||||
*format = 8;
|
|
||||||
return m_atomString;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CXWindowsClipboard::CICCCMGetClipboard
|
// CXWindowsClipboard::CICCCMGetClipboard
|
||||||
|
|
|
@ -5,12 +5,15 @@
|
||||||
#include "ClipboardTypes.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "stdmap.h"
|
#include "stdmap.h"
|
||||||
#include "stdlist.h"
|
#include "stdlist.h"
|
||||||
|
#include "stdvector.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
#else
|
#else
|
||||||
# include <X11/Xlib.h>
|
# include <X11/Xlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class IXWindowsClipboardConverter;
|
||||||
|
|
||||||
class CXWindowsClipboard : public IClipboard {
|
class CXWindowsClipboard : public IClipboard {
|
||||||
public:
|
public:
|
||||||
CXWindowsClipboard(Display*, Window, ClipboardID);
|
CXWindowsClipboard(Display*, Window, ClipboardID);
|
||||||
|
@ -51,6 +54,17 @@ public:
|
||||||
virtual CString get(EFormat) const;
|
virtual CString get(EFormat) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// remove all converters from our list
|
||||||
|
void clearConverters();
|
||||||
|
|
||||||
|
// get the converter for a clipboard format. returns NULL if no
|
||||||
|
// suitable converter. iff onlyIfNotAdded is true then also
|
||||||
|
// return NULL if a suitable converter was found but we already
|
||||||
|
// have data of the converter's clipboard format.
|
||||||
|
IXWindowsClipboardConverter*
|
||||||
|
getConverter(Atom target,
|
||||||
|
bool onlyIfNotAdded = false) const;
|
||||||
|
|
||||||
// convert target atom to clipboard format
|
// convert target atom to clipboard format
|
||||||
EFormat getFormat(Atom target) const;
|
EFormat getFormat(Atom target) const;
|
||||||
|
|
||||||
|
@ -218,9 +232,10 @@ private:
|
||||||
// data conversion methods
|
// data conversion methods
|
||||||
Atom getTargetsData(CString&, int* format) const;
|
Atom getTargetsData(CString&, int* format) const;
|
||||||
Atom getTimestampData(CString&, int* format) const;
|
Atom getTimestampData(CString&, int* format) const;
|
||||||
Atom getStringData(CString&, int* format) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef std::vector<IXWindowsClipboardConverter*> ConverterList;
|
||||||
|
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
Window m_window;
|
Window m_window;
|
||||||
ClipboardID m_id;
|
ClipboardID m_id;
|
||||||
|
@ -245,6 +260,9 @@ private:
|
||||||
CReplyMap m_replies;
|
CReplyMap m_replies;
|
||||||
CReplyEventMask m_eventMasks;
|
CReplyEventMask m_eventMasks;
|
||||||
|
|
||||||
|
// clipboard format converters
|
||||||
|
ConverterList m_converters;
|
||||||
|
|
||||||
// atoms we'll need
|
// atoms we'll need
|
||||||
Atom m_atomTargets;
|
Atom m_atomTargets;
|
||||||
Atom m_atomMultiple;
|
Atom m_atomMultiple;
|
||||||
|
@ -263,4 +281,31 @@ private:
|
||||||
Atom m_atomGDKSelection;
|
Atom m_atomGDKSelection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IXWindowsClipboardConverter : public IInterface {
|
||||||
|
public:
|
||||||
|
// accessors
|
||||||
|
|
||||||
|
// return the clipboard format this object converts from/to
|
||||||
|
virtual IClipboard::EFormat
|
||||||
|
getFormat() const = 0;
|
||||||
|
|
||||||
|
// return the atom representing the X selection format that
|
||||||
|
// this object converts from/to
|
||||||
|
virtual Atom getAtom() const = 0;
|
||||||
|
|
||||||
|
// return the size (in bits) of data elements returned by
|
||||||
|
// toIClipboard().
|
||||||
|
virtual int getDataSize() const = 0;
|
||||||
|
|
||||||
|
// convert from the IClipboard format to the X selection format.
|
||||||
|
// the input data must be in the IClipboard format returned by
|
||||||
|
// getFormat(). the return data will be in the X selection
|
||||||
|
// format returned by getAtom().
|
||||||
|
virtual CString fromIClipboard(const CString&) const = 0;
|
||||||
|
|
||||||
|
// convert from the X selection format to the IClipboard format
|
||||||
|
// (i.e., the reverse of fromIClipboard()).
|
||||||
|
virtual CString toIClipboard(const CString&) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "CXWindowsClipboardTextConverter.h"
|
||||||
|
#include "CUnicode.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CXWindowsClipboardTextConverter
|
||||||
|
//
|
||||||
|
|
||||||
|
CXWindowsClipboardTextConverter::CXWindowsClipboardTextConverter(
|
||||||
|
Display* display, const char* name) :
|
||||||
|
m_atom(XInternAtom(display, name, False))
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsClipboardTextConverter::~CXWindowsClipboardTextConverter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
IClipboard::EFormat
|
||||||
|
CXWindowsClipboardTextConverter::getFormat() const
|
||||||
|
{
|
||||||
|
return IClipboard::kText;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom
|
||||||
|
CXWindowsClipboardTextConverter::getAtom() const
|
||||||
|
{
|
||||||
|
return m_atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CXWindowsClipboardTextConverter::getDataSize() const
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CXWindowsClipboardTextConverter::fromIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::UTF8ToText(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CXWindowsClipboardTextConverter::toIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::textToUTF8(data);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef CXWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||||
|
#define CXWINDOWSCLIPBOARDTEXTCONVERTER_H
|
||||||
|
|
||||||
|
#include "CXWindowsClipboard.h"
|
||||||
|
|
||||||
|
class CXWindowsClipboardTextConverter : public IXWindowsClipboardConverter {
|
||||||
|
public:
|
||||||
|
CXWindowsClipboardTextConverter(Display* display, const char* name);
|
||||||
|
virtual ~CXWindowsClipboardTextConverter();
|
||||||
|
|
||||||
|
// IXWindowsClipboardConverter overrides
|
||||||
|
virtual IClipboard::EFormat
|
||||||
|
getFormat() const;
|
||||||
|
virtual Atom getAtom() const;
|
||||||
|
virtual int getDataSize() const;
|
||||||
|
virtual CString fromIClipboard(const CString&) const;
|
||||||
|
virtual CString toIClipboard(const CString&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Atom m_atom;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
#include "CXWindowsClipboardUCS2Converter.h"
|
||||||
|
#include "CUnicode.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CXWindowsClipboardUCS2Converter
|
||||||
|
//
|
||||||
|
|
||||||
|
CXWindowsClipboardUCS2Converter::CXWindowsClipboardUCS2Converter(
|
||||||
|
Display* display, const char* name) :
|
||||||
|
m_atom(XInternAtom(display, name, False))
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsClipboardUCS2Converter::~CXWindowsClipboardUCS2Converter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
IClipboard::EFormat
|
||||||
|
CXWindowsClipboardUCS2Converter::getFormat() const
|
||||||
|
{
|
||||||
|
return IClipboard::kText;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom
|
||||||
|
CXWindowsClipboardUCS2Converter::getAtom() const
|
||||||
|
{
|
||||||
|
return m_atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CXWindowsClipboardUCS2Converter::getDataSize() const
|
||||||
|
{
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CXWindowsClipboardUCS2Converter::fromIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::UTF8ToUCS2(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CXWindowsClipboardUCS2Converter::toIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return CUnicode::UCS2ToUTF8(data);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef CXWINDOWSCLIPBOARDUCS2CONVERTER_H
|
||||||
|
#define CXWINDOWSCLIPBOARDUCS2CONVERTER_H
|
||||||
|
|
||||||
|
#include "CXWindowsClipboard.h"
|
||||||
|
|
||||||
|
class CXWindowsClipboardUCS2Converter : public IXWindowsClipboardConverter {
|
||||||
|
public:
|
||||||
|
CXWindowsClipboardUCS2Converter(Display* display, const char* name);
|
||||||
|
virtual ~CXWindowsClipboardUCS2Converter();
|
||||||
|
|
||||||
|
// IXWindowsClipboardConverter overrides
|
||||||
|
virtual IClipboard::EFormat
|
||||||
|
getFormat() const;
|
||||||
|
virtual Atom getAtom() const;
|
||||||
|
virtual int getDataSize() const;
|
||||||
|
virtual CString fromIClipboard(const CString&) const;
|
||||||
|
virtual CString toIClipboard(const CString&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Atom m_atom;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "CXWindowsClipboardUTF8Converter.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CXWindowsClipboardUTF8Converter
|
||||||
|
//
|
||||||
|
|
||||||
|
CXWindowsClipboardUTF8Converter::CXWindowsClipboardUTF8Converter(
|
||||||
|
Display* display, const char* name) :
|
||||||
|
m_atom(XInternAtom(display, name, False))
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsClipboardUTF8Converter::~CXWindowsClipboardUTF8Converter()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
IClipboard::EFormat
|
||||||
|
CXWindowsClipboardUTF8Converter::getFormat() const
|
||||||
|
{
|
||||||
|
return IClipboard::kText;
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom
|
||||||
|
CXWindowsClipboardUTF8Converter::getAtom() const
|
||||||
|
{
|
||||||
|
return m_atom;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CXWindowsClipboardUTF8Converter::getDataSize() const
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CXWindowsClipboardUTF8Converter::fromIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CXWindowsClipboardUTF8Converter::toIClipboard(const CString& data) const
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef CXWINDOWSCLIPBOARDUTF8CONVERTER_H
|
||||||
|
#define CXWINDOWSCLIPBOARDUTF8CONVERTER_H
|
||||||
|
|
||||||
|
#include "CXWindowsClipboard.h"
|
||||||
|
|
||||||
|
class CXWindowsClipboardUTF8Converter : public IXWindowsClipboardConverter {
|
||||||
|
public:
|
||||||
|
CXWindowsClipboardUTF8Converter(Display* display, const char* name);
|
||||||
|
virtual ~CXWindowsClipboardUTF8Converter();
|
||||||
|
|
||||||
|
// IXWindowsClipboardConverter overrides
|
||||||
|
virtual IClipboard::EFormat
|
||||||
|
getFormat() const;
|
||||||
|
virtual Atom getAtom() const;
|
||||||
|
virtual int getDataSize() const;
|
||||||
|
virtual CString fromIClipboard(const CString&) const;
|
||||||
|
virtual CString toIClipboard(const CString&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Atom m_atom;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -4,22 +4,28 @@ DEPTH = ..
|
||||||
|
|
||||||
# FIXME -- add CUnixPlatform.cpp as an unbuilt source
|
# FIXME -- add CUnixPlatform.cpp as an unbuilt source
|
||||||
noinst_LIBRARIES = libplatform.a
|
noinst_LIBRARIES = libplatform.a
|
||||||
libplatform_a_SOURCES = \
|
libplatform_a_SOURCES = \
|
||||||
CPlatform.cpp \
|
CPlatform.cpp \
|
||||||
CXWindowsClipboard.cpp \
|
CXWindowsClipboard.cpp \
|
||||||
CXWindowsScreen.cpp \
|
CXWindowsClipboardTextConverter.cpp \
|
||||||
CXWindowsScreenSaver.cpp \
|
CXWindowsClipboardUCS2Converter.cpp \
|
||||||
CXWindowsUtil.cpp \
|
CXWindowsClipboardUTF8Converter.cpp \
|
||||||
CPlatform.h \
|
CXWindowsScreen.cpp \
|
||||||
CUnixPlatform.h \
|
CXWindowsScreenSaver.cpp \
|
||||||
CXWindowsClipboard.h \
|
CXWindowsUtil.cpp \
|
||||||
CXWindowsScreen.h \
|
CPlatform.h \
|
||||||
CXWindowsScreenSaver.h \
|
CUnixPlatform.h \
|
||||||
CXWindowsUtil.h \
|
CXWindowsClipboard.h \
|
||||||
IPlatform.h \
|
CXWindowsClipboardTextConverter.h \
|
||||||
|
CXWindowsClipboardUCS2Converter.h \
|
||||||
|
CXWindowsClipboardUTF8Converter.h \
|
||||||
|
CXWindowsScreen.h \
|
||||||
|
CXWindowsScreenSaver.h \
|
||||||
|
CXWindowsUtil.h \
|
||||||
|
IPlatform.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
-I$(DEPTH)/base \
|
-I$(DEPTH)/base \
|
||||||
-I$(DEPTH)/mt \
|
-I$(DEPTH)/mt \
|
||||||
-I$(DEPTH)/synergy \
|
-I$(DEPTH)/synergy \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -13,7 +13,13 @@ public:
|
||||||
typedef UInt32 Time;
|
typedef UInt32 Time;
|
||||||
|
|
||||||
// known clipboard formats. kNumFormats must be last and
|
// known clipboard formats. kNumFormats must be last and
|
||||||
// formats must be sequential starting from zero.
|
// formats must be sequential starting from zero. clipboard
|
||||||
|
// data set via add() and retrieved via get() is in one of
|
||||||
|
// these formats. platform dependent clipboard subclasses
|
||||||
|
// can and should present any suitable formats derivable
|
||||||
|
// from these formats (e.g. UCS-16 encoded unicode).
|
||||||
|
//
|
||||||
|
// kText: UTF-8 encoded unicode (ISO-10646), newline is LF
|
||||||
enum EFormat { kText, kNumFormats };
|
enum EFormat { kText, kNumFormats };
|
||||||
|
|
||||||
// manipulators
|
// manipulators
|
||||||
|
|
Loading…
Reference in New Issue