gui-win32: fix encoding and decoding of clipboard strings
On Windows, the clipboard strings are encoded in UTF-16. However, Drawterm considers them as Rune. It used to work when a Rune was a short, but a Rune is now a int. The solution is to implement Rune16 functions to handle UTF-16 strings. The Rune16 functions were written by Charles Forsyth as part of Inferno. Balaji Srinivasa integrated them into Drawterm.
This commit is contained in:
parent
164f930802
commit
8de603bff1
|
@ -7,7 +7,8 @@ OFILES=\
|
||||||
cload.$O\
|
cload.$O\
|
||||||
draw.$O\
|
draw.$O\
|
||||||
load.$O\
|
load.$O\
|
||||||
screen.$O
|
screen.$O\
|
||||||
|
r16.$O
|
||||||
|
|
||||||
default: $(LIB)
|
default: $(LIB)
|
||||||
$(LIB): $(OFILES)
|
$(LIB): $(OFILES)
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
#define _WIN32_WINNT 0x0500
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include "r16.h"
|
||||||
|
|
||||||
|
#define Bit(i) (7-(i))
|
||||||
|
/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */
|
||||||
|
#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF)
|
||||||
|
/* 0000 0000 0000 0111 1111 1111 */
|
||||||
|
#define RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Bitx = Bit(1),
|
||||||
|
|
||||||
|
Tx = T(1), /* 1000 0000 */
|
||||||
|
Rune1 = (1<<(Bit(0)+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */
|
||||||
|
|
||||||
|
Maskx = (1<<Bitx)-1, /* 0011 1111 */
|
||||||
|
Testx = Maskx ^ 0xFF, /* 1100 0000 */
|
||||||
|
|
||||||
|
SurrogateMin = 0xD800,
|
||||||
|
SurrogateMax = 0xDFFF,
|
||||||
|
|
||||||
|
Bad = Runeerror,
|
||||||
|
};
|
||||||
|
|
||||||
|
Rune16*
|
||||||
|
runes16dup(Rune16 *r)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
Rune16 *s;
|
||||||
|
|
||||||
|
n = runes16len(r) + 1;
|
||||||
|
s = malloc(n * sizeof(Rune16));
|
||||||
|
memmove(s, r, n * sizeof(Rune16));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
runes16len(Rune16 *r)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
while(*r++ != 0)
|
||||||
|
n++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
runes16toutf(char *p, Rune16 *r, int nc)
|
||||||
|
{
|
||||||
|
char *op, *ep;
|
||||||
|
int n, c;
|
||||||
|
Rune rc;
|
||||||
|
|
||||||
|
op = p;
|
||||||
|
ep = p + nc;
|
||||||
|
while(c = *r++) {
|
||||||
|
n = 1;
|
||||||
|
if(c >= Runeself)
|
||||||
|
n = runelen(c);
|
||||||
|
if(p + n >= ep)
|
||||||
|
break;
|
||||||
|
rc = c;
|
||||||
|
if(c < Runeself)
|
||||||
|
*p++ = c;
|
||||||
|
else
|
||||||
|
p += runetochar(p, &rc);
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rune16nlen(Rune16 *r, int nrune)
|
||||||
|
{
|
||||||
|
int nb, i;
|
||||||
|
Rune c;
|
||||||
|
|
||||||
|
nb = 0;
|
||||||
|
while(nrune--) {
|
||||||
|
c = *r++;
|
||||||
|
if(c <= Rune1){
|
||||||
|
nb++;
|
||||||
|
} else {
|
||||||
|
for(i = 2; i < UTFmax + 1; i++)
|
||||||
|
if(c <= RuneX(i) || i == UTFmax){
|
||||||
|
nb += i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nb;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rune16*
|
||||||
|
utftorunes16(Rune16 *r, char *p, int nc)
|
||||||
|
{
|
||||||
|
Rune16 *or, *er;
|
||||||
|
Rune rc;
|
||||||
|
|
||||||
|
or = r;
|
||||||
|
er = r + nc;
|
||||||
|
while(*p != '\0' && r + 1 < er){
|
||||||
|
p += chartorune(&rc, p);
|
||||||
|
*r++ = rc; /* we'll ignore surrogate pairs */
|
||||||
|
}
|
||||||
|
*r = '\0';
|
||||||
|
return or;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
runes16cmp(Rune16 *s1, Rune16 *s2)
|
||||||
|
{
|
||||||
|
Rune16 r1, r2;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
r1 = *s1++;
|
||||||
|
r2 = *s2++;
|
||||||
|
if(r1 != r2) {
|
||||||
|
if(r1 > r2)
|
||||||
|
return 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(r1 == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *
|
||||||
|
widen(char *s)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
wchar_t *ws;
|
||||||
|
|
||||||
|
n = utflen(s) + 1;
|
||||||
|
ws = smalloc(n*sizeof(wchar_t));
|
||||||
|
utftorunes16(ws, s, n);
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
narrowen(wchar_t *ws)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = widebytes(ws);
|
||||||
|
s = smalloc(n);
|
||||||
|
runes16toutf(s, ws, n);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
widebytes(wchar_t *ws)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
while (*ws)
|
||||||
|
n += runelen(*ws++);
|
||||||
|
return n+1;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
typedef unsigned short Rune16;
|
||||||
|
|
||||||
|
wchar_t *widen(char *s);
|
||||||
|
char *narrowen(wchar_t *ws);
|
||||||
|
int widebytes(wchar_t *ws);
|
||||||
|
int runes16len(Rune16*);
|
||||||
|
int rune16nlen(Rune16*, int);
|
||||||
|
Rune16* runes16dup(Rune16*);
|
||||||
|
Rune16* utftorunes16(Rune16*, char*, int);
|
||||||
|
char* runes16toutf(char*, Rune16*, int);
|
||||||
|
int runes16cmp(Rune16*, Rune16*);
|
|
@ -14,6 +14,7 @@
|
||||||
#include <memdraw.h>
|
#include <memdraw.h>
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
|
#include "r16.h"
|
||||||
|
|
||||||
Memimage *gscreen;
|
Memimage *gscreen;
|
||||||
Screeninfo screen;
|
Screeninfo screen;
|
||||||
|
@ -544,14 +545,14 @@ setcolor(ulong index, ulong red, ulong green, ulong blue)
|
||||||
uchar*
|
uchar*
|
||||||
clipreadunicode(HANDLE h)
|
clipreadunicode(HANDLE h)
|
||||||
{
|
{
|
||||||
Rune *p;
|
Rune16 *p;
|
||||||
int n;
|
int n;
|
||||||
uchar *q;
|
uchar *q;
|
||||||
|
|
||||||
p = GlobalLock(h);
|
p = GlobalLock(h);
|
||||||
n = wstrutflen(p)+1;
|
n = rune16nlen(p, runes16len(p)+1);
|
||||||
q = malloc(n);
|
q = malloc(n);
|
||||||
wstrtoutf(q, p, n);
|
runes16toutf(q, p, n);
|
||||||
GlobalUnlock(h);
|
GlobalUnlock(h);
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
|
@ -598,7 +599,7 @@ clipwrite(char *buf)
|
||||||
{
|
{
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
char *p, *e;
|
char *p, *e;
|
||||||
Rune *rp;
|
Rune16 *rp;
|
||||||
int n = strlen(buf);
|
int n = strlen(buf);
|
||||||
|
|
||||||
if(!OpenClipboard(window)) {
|
if(!OpenClipboard(window)) {
|
||||||
|
@ -616,11 +617,7 @@ clipwrite(char *buf)
|
||||||
if(h == NULL)
|
if(h == NULL)
|
||||||
panic("out of memory");
|
panic("out of memory");
|
||||||
rp = GlobalLock(h);
|
rp = GlobalLock(h);
|
||||||
p = buf;
|
utftorunes16(rp, buf, n+1);
|
||||||
e = p+n;
|
|
||||||
while(p<e)
|
|
||||||
p += chartorune(rp++, p);
|
|
||||||
*rp = 0;
|
|
||||||
GlobalUnlock(h);
|
GlobalUnlock(h);
|
||||||
|
|
||||||
SetClipboardData(CF_UNICODETEXT, h);
|
SetClipboardData(CF_UNICODETEXT, h);
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
#include <u.h>
|
|
||||||
#include <libc.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
wstrutflen(Rune *s)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
for(n=0; *s; n+=runelen(*s),s++)
|
|
||||||
;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
wstrtoutf(char *s, Rune *t, int n)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *s0;
|
|
||||||
|
|
||||||
s0 = s;
|
|
||||||
if(n <= 0)
|
|
||||||
return wstrutflen(t)+1;
|
|
||||||
while(*t) {
|
|
||||||
if(n < UTFmax+1 && n < runelen(*t)+1) {
|
|
||||||
*s = 0;
|
|
||||||
return i+wstrutflen(t)+1;
|
|
||||||
}
|
|
||||||
i = runetochar(s, t);
|
|
||||||
s += i;
|
|
||||||
n -= i;
|
|
||||||
t++;
|
|
||||||
}
|
|
||||||
*s = 0;
|
|
||||||
return s-s0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue