]> source.dussan.org Git - tigervnc.git/commitdiff
Add UTF-8 to/from ISO 8859-1 conversion routines
authorPierre Ossman <ossman@cendio.se>
Fri, 22 Jan 2016 15:40:59 +0000 (16:40 +0100)
committerPierre Ossman <ossman@cendio.se>
Mon, 1 Jul 2019 08:49:15 +0000 (10:49 +0200)
We convert between UTF-8 and ISO 8859-1 (latin 1) in several places
so create some common routines for this.

common/rfb/util.cxx
common/rfb/util.h
unix/xserver/hw/vnc/RFBGlue.cc
unix/xserver/hw/vnc/RFBGlue.h
unix/xserver/hw/vnc/vncSelection.c
vncviewer/Viewport.cxx
vncviewer/Viewport.h

index f43a9453916e0380a8701510c735b62d46dbe4c2..deb68ca196068ad106f1c358f8987e49a867c145 100644 (file)
@@ -163,6 +163,172 @@ namespace rfb {
     return buffer;
   }
 
+  size_t ucs4ToUTF8(unsigned src, char* dst) {
+    if (src < 0x80) {
+      *dst++ = src;
+      *dst++ = '\0';
+      return 1;
+    } else if (src < 0x800) {
+      *dst++ = 0xc0 | (src >> 6);
+      *dst++ = 0x80 | (src & 0x3f);
+      *dst++ = '\0';
+      return 2;
+    } else if (src < 0x10000) {
+      *dst++ = 0xe0 | (src >> 12);
+      *dst++ = 0x80 | ((src >> 6) & 0x3f);
+      *dst++ = 0x80 | (src & 0x3f);
+      *dst++ = '\0';
+      return 3;
+    } else if (src < 0x110000) {
+      *dst++ = 0xf0 | (src >> 18);
+      *dst++ = 0x80 | ((src >> 12) & 0x3f);
+      *dst++ = 0x80 | ((src >> 6) & 0x3f);
+      *dst++ = 0x80 | (src & 0x3f);
+      *dst++ = '\0';
+      return 4;
+    } else {
+      return ucs4ToUTF8(0xfffd, dst);
+    }
+  }
+
+  size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst) {
+    size_t count, consumed;
+
+    *dst = 0xfffd;
+
+    if (max == 0)
+      return 0;
+
+    consumed = 1;
+
+    if ((*src & 0x80) == 0) {
+      *dst = *src;
+      count = 0;
+    } else if ((*src & 0xe0) == 0xc0) {
+      *dst = *src & 0x1f;
+      count = 1;
+    } else if ((*src & 0xf0) == 0xe0) {
+      *dst = *src & 0x0f;
+      count = 2;
+    } else if ((*src & 0xf8) == 0xf0) {
+      *dst = *src & 0x07;
+      count = 3;
+    } else {
+      // Invalid sequence, consume all continuation characters
+      src++;
+      max--;
+      while ((max-- > 0) && ((*src++ & 0xc0) == 0x80))
+        consumed++;
+      return consumed;
+    }
+
+    src++;
+    max--;
+
+    while (count--) {
+      // Invalid or truncated sequence?
+      if ((max == 0) || ((*src & 0xc0) != 0x80)) {
+        *dst = 0xfffd;
+        return consumed;
+      }
+
+      *dst <<= 6;
+      *dst |= *src & 0x3f;
+
+      src++;
+      max--;
+    }
+
+    return consumed;
+  }
+
+  char* latin1ToUTF8(const char* src, size_t bytes) {
+    char* buffer;
+    size_t sz;
+
+    char* out;
+    const char* in;
+    size_t in_len;
+
+    // Always include space for a NULL
+    sz = 1;
+
+    // Compute output size
+    in = src;
+    in_len = bytes;
+    while ((*in != '\0') && (in_len > 0)) {
+      char buf[5];
+      sz += ucs4ToUTF8(*in, buf);
+      in++;
+      in_len--;
+    }
+
+    // Alloc
+    buffer = new char[sz];
+    memset(buffer, 0, sz);
+
+    // And convert
+    out = buffer;
+    in = src;
+    in_len = bytes;
+    while ((*in != '\0') && (in_len > 0)) {
+      out += ucs4ToUTF8(*in, out);
+      in++;
+      in_len--;
+    }
+
+    return buffer;
+  }
+
+  char* utf8ToLatin1(const char* src, size_t bytes) {
+    char* buffer;
+    size_t sz;
+
+    char* out;
+    const char* in;
+    size_t in_len;
+
+    // Always include space for a NULL
+    sz = 1;
+
+    // Compute output size
+    in = src;
+    in_len = bytes;
+    while ((*in != '\0') && (in_len > 0)) {
+      size_t len;
+      unsigned ucs;
+
+      len = utf8ToUCS4(in, in_len, &ucs);
+      in += len;
+      in_len -= len;
+      sz++;
+    }
+
+    // Alloc
+    buffer = new char[sz];
+    memset(buffer, 0, sz);
+
+    // And convert
+    out = buffer;
+    in = src;
+    in_len = bytes;
+    while ((*in != '\0') && (in_len > 0)) {
+      size_t len;
+      unsigned ucs;
+
+      len = utf8ToUCS4(in, in_len, &ucs);
+      in += len;
+      in_len -= len;
+
+      if (ucs > 0xff)
+        *out++ = '?';
+      else
+        *out++ = (unsigned char)ucs;
+    }
+
+    return buffer;
+  }
+
   unsigned msBetween(const struct timeval *first,
                      const struct timeval *second)
   {
index de096692cf12c55a32092b6f376182efe9315bbe..7bd5cc011fabbbb007e6d6ce4443cc4b27d4f983 100644 (file)
@@ -88,6 +88,15 @@ namespace rfb {
 
   char* convertLF(const char* src, size_t bytes = (size_t)-1);
 
+  // Convertions between various Unicode formats. The returned strings are
+  // always null terminated and must be freed using strFree().
+
+  size_t ucs4ToUTF8(unsigned src, char* dst);
+  size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst);
+
+  char* latin1ToUTF8(const char* src, size_t bytes = (size_t)-1);
+  char* utf8ToLatin1(const char* src, size_t bytes = (size_t)-1);
+
   // HELPER functions for timeout handling
 
   // soonestTimeout() is a function to help work out the soonest of several
index d9c456e859bff67c1a3ba296663a0cc43593aa18..f108fae4353a8576548163ca347c2a97138d4501 100644 (file)
@@ -220,6 +220,24 @@ char* vncConvertLF(const char* src, size_t bytes)
   }
 }
 
+char* vncLatin1ToUTF8(const char* src, size_t bytes)
+{
+  try {
+    return latin1ToUTF8(src, bytes);
+  } catch (...) {
+    return NULL;
+  }
+}
+
+char* vncUTF8ToLatin1(const char* src, size_t bytes)
+{
+  try {
+    return utf8ToLatin1(src, bytes);
+  } catch (...) {
+    return NULL;
+  }
+}
+
 void vncStrFree(char* str)
 {
   strFree(str);
index 8e70c680985a1e5c1b4a5914c70ff1f252f84a7f..112405b8479352aaea2af13838e8580aea90c173 100644 (file)
@@ -50,6 +50,10 @@ int vncGetSocketPort(int fd);
 int vncIsTCPPortUsed(int port);
 
 char* vncConvertLF(const char* src, size_t bytes);
+
+char* vncLatin1ToUTF8(const char* src, size_t bytes);
+char* vncUTF8ToLatin1(const char* src, size_t bytes);
+
 void vncStrFree(char* str);
 
 #ifdef __cplusplus
index 8f4146d9eaeb458159d44789219f61b2da55c222..3438ac8640679dc4ba53301fd81072313625616b 100644 (file)
@@ -247,36 +247,16 @@ static int vncConvertSelection(ClientPtr client, Atom selection,
     if (rc != Success)
       return rc;
   } else if (target == xaUTF8_STRING) {
-    unsigned char* buffer;
-    unsigned char* out;
-    size_t len;
+    char* buffer;
 
-    const unsigned char* in;
-    size_t in_len;
-
-    buffer = malloc(strlen(clientCutText)*2);
+    buffer = vncLatin1ToUTF8(clientCutText, (size_t)-1);
     if (buffer == NULL)
       return BadAlloc;
 
-    out = buffer;
-    len = 0;
-    in = clientCutText;
-    while (*in != '\0') {
-      if (*in & 0x80) {
-        *out++ = 0xc0 | (*in >> 6);
-        *out++ = 0x80 | (*in & 0x3f);
-        len += 2;
-        in++;
-      } else {
-        *out++ = *in++;
-        len++;
-      }
-    }
-
     rc = dixChangeWindowProperty(serverClient, pWin, realProperty,
                                  xaUTF8_STRING, 8, PropModeReplace,
-                                 len, buffer, TRUE);
-    free(buffer);
+                                 strlen(buffer), buffer, TRUE);
+    vncStrFree(buffer);
     if (rc != Success)
       return rc;
   } else {
@@ -424,56 +404,19 @@ static void vncHandleSelection(Atom selection, Atom target,
     vncStrFree(filtered);
   } else if (target == xaUTF8_STRING) {
     char *filtered;
-    unsigned char* buffer;
-    unsigned char* out;
-    size_t len;
-
-    const unsigned char* in;
-    size_t in_len;
+    char* buffer;
 
     if (prop->format != 8)
       return;
     if (prop->type != xaUTF8_STRING)
       return;
 
-    buffer = malloc(prop->size);
+    buffer = vncUTF8ToLatin1(prop->data, prop->size);
     if (buffer == NULL)
       return;
 
-    out = buffer;
-    len = 0;
-    in = prop->data;
-    in_len = prop->size;
-    while (in_len > 0) {
-      if ((*in & 0x80) == 0x00) {
-        *out++ = *in++;
-        len++;
-        in_len--;
-      } else if ((*in & 0xe0) == 0xc0) {
-        unsigned ucs;
-        ucs = (*in++ & 0x1f) << 6;
-        in_len--;
-        if (in_len > 0) {
-          ucs |= (*in++ & 0x3f);
-          in_len--;
-        }
-        if (ucs <= 0xff)
-          *out++ = ucs;
-        else
-          *out++ = '?';
-        len++;
-      } else {
-        *out++ = '?';
-        len++;
-        do {
-          in++;
-          in_len--;
-        } while ((in_len > 0) && ((*in & 0xc0) == 0x80));
-      }
-    }
-
-    filtered = vncConvertLF(buffer, len);
-    free(buffer);
+    filtered = vncConvertLF(buffer, (size_t)-1);
+    vncStrFree(buffer);
     if (filtered == NULL)
       return;
 
index 5e495992e0c556670ba872fb784d603e20b651da..151ecb47b009319f0c9397edc46fa4f78bcd88e9 100644 (file)
@@ -235,25 +235,17 @@ void Viewport::updateWindow()
 void Viewport::serverCutText(const char* str)
 {
   char *buffer;
-  int size, ret;
+  size_t len;
 
   clearPendingClipboard();
 
   if (!acceptClipboard)
     return;
 
-  size = fl_utf8froma(NULL, 0, str, strlen(str));
-  if (size <= 0)
-    return;
-
-  size++;
-
-  buffer = new char[size];
+  buffer = latin1ToUTF8(str);
+  len = strlen(buffer);
 
-  ret = fl_utf8froma(buffer, size, str, strlen(str));
-  assert(ret < size);
-
-  vlog.debug("Got clipboard data (%d bytes)", (int)strlen(buffer));
+  vlog.debug("Got clipboard data (%d bytes)", (int)len);
 
   if (!hasFocus()) {
     pendingServerCutText = buffer;
@@ -264,11 +256,11 @@ void Viewport::serverCutText(const char* str)
   // dump the data into both variants.
 #if !defined(WIN32) && !defined(__APPLE__)
   if (setPrimary)
-    Fl::copy(buffer, ret, 0);
+    Fl::copy(buffer, len, 0);
 #endif
-  Fl::copy(buffer, ret, 1);
+  Fl::copy(buffer, len, 1);
 
-  delete [] buffer;
+  strFree(buffer);
 }
 
 static const char * dotcursor_xpm[] = {
@@ -550,27 +542,19 @@ void Viewport::resize(int x, int y, int w, int h)
 int Viewport::handle(int event)
 {
   char *buffer, *filtered;
-  int ret;
   int buttonMask, wheelMask;
   DownMap::const_iterator iter;
 
   switch (event) {
   case FL_PASTE:
-    buffer = new char[Fl::event_length() + 1];
-
     clearPendingClipboard();
 
-    // This is documented as to ASCII, but actually does to 8859-1
-    ret = fl_utf8toa(Fl::event_text(), Fl::event_length(), buffer,
-                     Fl::event_length() + 1);
-    assert(ret < (Fl::event_length() + 1));
-    filtered = convertLF(buffer, ret);
-    delete [] buffer;
+    buffer = utf8ToLatin1(Fl::event_text(), Fl::event_length());
+    filtered = convertLF(buffer);
+    strFree(buffer);
 
     if (!hasFocus()) {
-      pendingClientCutText = new char[strlen(filtered) + 1];
-      strcpy((char*)pendingClientCutText, filtered);
-      strFree(filtered);
+      pendingClientCutText = filtered;
       return 1;
     }
 
@@ -747,9 +731,9 @@ void Viewport::handleClipboardChange(int source, void *data)
 
 void Viewport::clearPendingClipboard()
 {
-  delete [] pendingServerCutText;
+  strFree(pendingServerCutText);
   pendingServerCutText = NULL;
-  delete [] pendingClientCutText;
+  strFree(pendingClientCutText);
   pendingClientCutText = NULL;
 }
 
index c2c9872e399e22ed02b0c57088eeff1a86b75087..8b9b469b6b981a632642d2be7da4bc86c21adfc8 100644 (file)
@@ -114,8 +114,8 @@ private:
 
   bool firstLEDState;
 
-  const char* pendingServerCutText;
-  const char* pendingClientCutText;
+  char* pendingServerCutText;
+  char* pendingClientCutText;
 
   rdr::U32 menuKeySym;
   int menuKeyCode, menuKeyFLTK;