From 8de603bff116425d9a0943f97898d565a82311a8 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 17 Jun 2015 22:40:15 +0200 Subject: [PATCH] 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. --- gui-win32/Makefile | 3 +- gui-win32/r16.c | 168 ++++++++++++++++++++++++++++++++++++++++++ gui-win32/r16.h | 11 +++ gui-win32/screen.c | 17 ++--- gui-win32/wstrtoutf.c | 35 --------- 5 files changed, 188 insertions(+), 46 deletions(-) create mode 100644 gui-win32/r16.c create mode 100644 gui-win32/r16.h delete mode 100644 gui-win32/wstrtoutf.c diff --git a/gui-win32/Makefile b/gui-win32/Makefile index 1054760..50514f0 100644 --- a/gui-win32/Makefile +++ b/gui-win32/Makefile @@ -7,7 +7,8 @@ OFILES=\ cload.$O\ draw.$O\ load.$O\ - screen.$O + screen.$O\ + r16.$O default: $(LIB) $(LIB): $(OFILES) diff --git a/gui-win32/r16.c b/gui-win32/r16.c new file mode 100644 index 0000000..9de6783 --- /dev/null +++ b/gui-win32/r16.c @@ -0,0 +1,168 @@ +#define _WIN32_WINNT 0x0500 +#include + +#include +#include +#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<= 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; +} diff --git a/gui-win32/r16.h b/gui-win32/r16.h new file mode 100644 index 0000000..ea4ee28 --- /dev/null +++ b/gui-win32/r16.h @@ -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*); diff --git a/gui-win32/screen.c b/gui-win32/screen.c index 0a656f2..c645086 100644 --- a/gui-win32/screen.c +++ b/gui-win32/screen.c @@ -14,6 +14,7 @@ #include #include "screen.h" #include "keyboard.h" +#include "r16.h" Memimage *gscreen; Screeninfo screen; @@ -544,14 +545,14 @@ setcolor(ulong index, ulong red, ulong green, ulong blue) uchar* clipreadunicode(HANDLE h) { - Rune *p; + Rune16 *p; int n; uchar *q; - + p = GlobalLock(h); - n = wstrutflen(p)+1; + n = rune16nlen(p, runes16len(p)+1); q = malloc(n); - wstrtoutf(q, p, n); + runes16toutf(q, p, n); GlobalUnlock(h); return q; @@ -598,7 +599,7 @@ clipwrite(char *buf) { HANDLE h; char *p, *e; - Rune *rp; + Rune16 *rp; int n = strlen(buf); if(!OpenClipboard(window)) { @@ -616,11 +617,7 @@ clipwrite(char *buf) if(h == NULL) panic("out of memory"); rp = GlobalLock(h); - p = buf; - e = p+n; - while(p -#include - -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; -}