Changeset: 849ea3a3e68c for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=849ea3a3e68c
Modified Files:
        clients/odbc/driver/ODBCUtil.c
        configure.ag
Branch: Aug2018
Log Message:

Updated ODBC UTF-8 handling.


diffs (truncated from 368 to 300 lines):

diff --git a/clients/odbc/driver/ODBCUtil.c b/clients/odbc/driver/ODBCUtil.c
--- a/clients/odbc/driver/ODBCUtil.c
+++ b/clients/odbc/driver/ODBCUtil.c
@@ -69,16 +69,6 @@ dupODBCstring(const SQLCHAR *inStr, size
        return tmp;
 }
 
-/* Conversion to and from SQLWCHAR */
-static int utf8chkmsk[] = {
-       0x0000007f,
-       0x00000780,
-       0x0000f800,
-       0x001f0000,
-       0x03e00000,
-       0x7c000000
-};
-
 /* Convert a SQLWCHAR (UTF-16 encoded string) to UTF-8.  On success,
    clears the location pointed to by errmsg and returns NULL or a
    newly allocated buffer.  On error, assigns a string with an error
@@ -89,77 +79,101 @@ static int utf8chkmsk[] = {
 SQLCHAR *
 ODBCwchar2utf8(const SQLWCHAR *src, SQLLEN length, const char **errmsg)
 {
-       const SQLWCHAR *s1, *e;
-       unsigned long c;
-       SQLCHAR *buf, *p;
-       int l, n;
+       size_t i = 0;
+       SQLLEN j = 0;
+       uint32_t c;
+       SQLCHAR *dest;
 
        if (errmsg)
                *errmsg = NULL;
-       if (s == NULL)
+       if (src == NULL || length == SQL_NULL_DATA)
                return NULL;
-       if (length == SQL_NTS)
-               for (s1 = s, length = 0; *s1; s1++)
-                       length++;
-       else if (length == SQL_NULL_DATA)
-               return NULL;
-       else if (length < 0) {
+       if (length == SQL_NTS) {
+               /* a very large (positive) number that fits in SQLLEN */
+               length = (SQLLEN) (~(SQLULEN)0 >> 1);
+       } else if (length < 0) {
                if (errmsg)
                        *errmsg = "Invalid length parameter";
                return NULL;
        }
-       e = s + length;
-       /* count necessary length */
-       l = 1;                  /* space for NULL byte */
-       for (s1 = s; s1 < e && *s1; s1++) {
-               c = *s1;
-               if (0xD800 <= c && c <= 0xDBFF) {
-                       /* high surrogate, must be followed by low surrogate */
-                       s1++;
-                       if (s1 >= e || *s1 < 0xDC00 || *s1 > 0xDFFF) {
+       while (j < length && src[j]) {
+               if (src[j] <= 0x7F) {
+                       i += 1;
+               } else if (src[j] <= 0x7FF) {
+                       i += 2;
+               } else if (
+#if SIZEOF_SQLWCHAR == 2
+                       (src[j] & 0xFC00) != 0xD800
+#else
+                       src[j] <= 0xFFFF
+#endif
+                       ) {
+                       if ((src[j] & 0xF800) == 0xD800) {
                                if (errmsg)
-                                       *errmsg = "High surrogate not followed 
by low surrogate";
+                                       *errmsg = "Illegal surrogate";
+                               return NULL;
+                       }
+                       i += 3;
+               } else {
+#if SIZEOF_SQLWCHAR == 2
+                       /* (src[j] & 0xFC00) == 0xD800, i.e. high surrogate */
+                       if ((src[j+1] & 0xFC00) != 0xDC00) {
+                               if (errmsg)
+                                       *errmsg = "Illegal surrogate";
+                               return NULL;
+                       }
+                       j++;
+#else
+                       c = src[j+0];
+                       if (c > 0x10FFFF || (c & 0x1FF800) == 0xD800) {
+                               if (errmsg)
+                                       *errmsg = "Illegal wide character 
value";
                                return NULL;
                        }
-                       c = (((c & 0x03FF) << 10) | (*s1 & 0x3FF)) + 0x10000;
-               } else if (0xDC00 <= c && c <= 0xDFFF) {
-                       /* low surrogate--illegal */
-                       if (errmsg)
-                               *errmsg = "Low surrogate not preceded by high 
surrogate";
-                       return NULL;
+#endif
+                       i += 4;
                }
-               for (n = 5; n > 0; n--)
-                       if (c & utf8chkmsk[n])
-                               break;
-               l += n + 1;
-       }
-       /* convert */
-       buf = (SQLCHAR *) malloc(l);
-       if (buf == NULL) {
-               if (errmsg)
-                       *errmsg = "Memory allocation error";
-               return NULL;
+               j++;
        }
-       for (s1 = s, p = buf; s1 < e && *s1; s1++) {
-               c = *s1;
-               if (0xD800 <= c && c <= 0xDBFF) {
-                       /* high surrogate followed by low surrogate */
-                       s1++;
-                       c = (((c & 0x03FF) << 10) | (*s1 & 0x3FF)) + 0x10000;
+       length = j;     /* figured out the real length (might not change) */
+       dest = malloc((i + 1) * sizeof(SQLCHAR));
+       if (dest == NULL)
+               return NULL;
+       i = 0;
+       j = 0;
+       while (j < length) {
+               if (src[j] <= 0x7F) {
+                       dest[i++] = src[j];
+               } else if (src[j] <= 0x7FF) {
+                       dest[i++] = 0xC0 | (src[j] >> 6);
+                       dest[i++] = 0x80 | (src[j] & 0x3F);
+               } else if (
+#if SIZEOF_SQLWCHAR == 2
+                       (src[j] & 0xFC00) != 0xD800
+#else
+                       src[j] <= 0xFFFF
+#endif
+                       ) {
+                       dest[i++] = 0xE0 | (src[j] >> 12);
+                       dest[i++] = 0x80 | ((src[j] >> 6) & 0x3F);
+                       dest[i++] = 0x80 | (src[j] & 0x3F);
+               } else {
+#if SIZEOF_SQLWCHAR == 2
+                       c = ((src[j+0] & 0x03FF) + 0x40) << 10
+                               | (src[j+1] & 0x03FF);
+                       j++;
+#else
+                       c = src[j+0];
+#endif
+                       dest[i++] = 0xF0 | (c >> 18);
+                       dest[i++] = 0x80 | ((c >> 12) & 0x3F);
+                       dest[i++] = 0x80 | ((c >> 6) & 0x3F);
+                       dest[i++] = 0x80 | (c & 0x3F);
                }
-               for (n = 5; n > 0; n--)
-                       if (c & utf8chkmsk[n])
-                               break;
-               if (n == 0)
-                       *p++ = (SQLCHAR) c;
-               else {
-                       *p++ = (SQLCHAR) (((c >> (n * 6)) | (0x1F80 >> n)) & 
0xFF);
-                       while (--n >= 0)
-                               *p++ = (SQLCHAR) (((c >> (n * 6)) & 0x3F) | 
0x80);
-               }
+               j++;
        }
-       *p = 0;
-       return buf;
+       dest[i] = 0;
+       return dest;
 }
 
 /* Convert a UTF-8 encoded string to UTF-16 (SQLWCHAR).  On success
@@ -167,81 +181,121 @@ ODBCwchar2utf8(const SQLWCHAR *src, SQLL
    first two arguments describe the input, the last three arguments
    describe the output, both in the normal ODBC fashion. */
 const char *
-ODBCutf82wchar(const SQLCHAR *s,
+ODBCutf82wchar(const SQLCHAR *src,
               SQLINTEGER length,
               SQLWCHAR *buf,
               SQLLEN buflen,
               SQLSMALLINT *buflenout)
 {
-       SQLWCHAR *p;
-       const SQLCHAR *e;
-       int m, n;
-       unsigned int c;
-       SQLSMALLINT len = 0;
+       SQLLEN i = 0;
+       SQLINTEGER j = 0;
+       uint32_t c;
 
-       if (s == NULL || length == SQL_NULL_DATA) {
-               if (buf && buflen > 0)
-                       *buf = 0;
+       if (buf == NULL)
+               buflen = 0;
+       else if (buflen == 0)
+               buf = NULL;
+
+       if (src == NULL || length == SQL_NULL_DATA) {
+               if (buflen > 0)
+                       buf[0] = 0;
                if (buflenout)
                        *buflenout = 0;
                return NULL;
        }
        if (length == SQL_NTS)
-               length = (SQLINTEGER) strlen((const char *) s);
+               length = (SQLINTEGER) (~(SQLUINTEGER)0 >> 1);
        else if (length < 0)
                return "Invalid length parameter";
 
-       if (buf == NULL)
-               buflen = 0;
-
-       for (p = buf, e = s + length; s < e; ) {
-               c = *s++;
-               if ((c & 0x80) != 0) {
-                       for (n = 0, m = 0x40; c & m; n++, m >>= 1)
-                               ;
-                       /* n now is number of 10xxxxxx bytes that
-                        * should follow */
-                       if (n == 0 || n >= 4)
-                               return "Illegal UTF-8 sequence";
-                       if (s + n > e)
-                               return "Truncated UTF-8 sequence";
-                       c &= ~(0xFFC0) >> n;
-                       while (--n >= 0) {
-                               c <<= 6;
-                               c |= *s++ & 0x3F;
-                       }
-               }
-               if (c > 0x10FFFF) {
-                       /* cannot encode as UTF-16 */
-                       return "Codepoint too large to be representable in 
UTF-16";
-               }
-               if ((c & 0x1FFF800) == 0xD800) {
-                       /* UTF-8 encoded high or low surrogate */
+       while (j < length && i + 1 < buflen && src[j]) {
+               if ((src[j+0] & 0x80) == 0) {
+                       buf[i++] = src[j+0];
+                       j += 1;
+               } else if (j + 1 < length
+                          && (src[j+0] & 0xE0) == 0xC0
+                          && (src[j+1] & 0xC0) == 0x80
+                          && (src[j+0] & 0x1E) != 0) {
+                       buf[i++] = (src[j+0] & 0x1F) << 6
+                               | (src[j+1] & 0x3F);
+                       j += 2;
+               } else if (j + 2 < length
+                          && (src[j+0] & 0xF0) == 0xE0
+                          && (src[j+1] & 0xC0) == 0x80
+                          && (src[j+2] & 0xC0) == 0x80
+                          && ((src[j+0] & 0x0F) != 0
+                              || (src[j+1] & 0x20) != 0)) {
+                       buf[i++] = (src[j+0] & 0x0F) << 12
+                               | (src[j+1] & 0x3F) << 6
+                               | (src[j+2] & 0x3F);
+                       j += 3;
+               } else if (j + 3 < length
+                          && (src[j+0] & 0xF8) == 0xF0
+                          && (src[j+1] & 0xC0) == 0x80
+                          && (src[j+2] & 0xC0) == 0x80
+                          && (src[j+3] & 0xC0) == 0x80
+                          && ((src[j+0] & 0x07) != 0
+                              || (src[j+1] & 0x30) != 0)) {
+                       c = (src[j+0] & 0x07) << 18
+                               | (src[j+1] & 0x3F) << 12
+                               | (src[j+2] & 0x3F) << 6
+                               | (src[j+3] & 0x3F);
+                       if (c > 0x10FFFF || (c & 0x1FF800) == 0x00D800)
+                               return "Illegal code point";
+#if SIZEOF_SQLWCHAR == 2
+                               if (i + 2 >= buflen)
+                                       break;
+                               buf[i++] = 0xD800 | ((c - 0x10000) >> 10);
+                               buf[i++] = 0xDC00 | (c & 0x3FF);
+#else
+                               buf[i++] = c;
+#endif
+                       j += 4;
+               } else {
                        return "Illegal code point";
                }
-               if (c <= 0xFFFF) {
-                       if (--buflen > 0 && p != NULL)
-                               *p++ = c;
-                       len++;
+       }
+       if (buflen > 0)
+               buf[i] = 0;
+       while (j < length && src[j]) {
+               i++;
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to