libwinpr-crt: implement unicode functions
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Wed, 23 May 2012 05:49:21 +0000 (01:49 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Wed, 23 May 2012 05:49:21 +0000 (01:49 -0400)
include/winpr/crt.h
include/winpr/string.h
winpr/crt/string.c
winpr/sspi/CredSSP/credssp.c

index 498d357..57d9a25 100644 (file)
 
 #include <winpr/winpr.h>
 
+#ifdef _WIN32
+#include <winnls.h>
+#endif
+
 #include <winpr/string.h>
 
 #endif /* WINPR_CRT_H */
index 2c94f03..f108400 100644 (file)
 
 #ifndef _WIN32
 
+#define CSTR_LESS_THAN                 1
+#define CSTR_EQUAL                     2
+#define CSTR_GREATER_THAN              3
+
+#define CP_ACP                         0
+#define CP_OEMCP                       1
+#define CP_MACCP                       2
+#define CP_THREAD_ACP                  3
+#define CP_SYMBOL                      42
+#define CP_UTF7                                65000
+#define CP_UTF8                                65001
+
+#define MB_PRECOMPOSED                 0x00000001
+#define MB_COMPOSITE                   0x00000002
+#define MB_USEGLYPHCHARS               0x00000004
+#define MB_ERR_INVALID_CHARS           0x00000008
+
 WINPR_API char* _strdup(const char* strSource);
 WINPR_API wchar_t* _wcsdup(const wchar_t* strSource);
 
@@ -102,6 +119,12 @@ WINPR_API BOOL IsCharLowerW(WCHAR ch);
 #define IsCharLower    IsCharLowerA
 #endif
 
+WINPR_API int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
+               int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
+
+WINPR_API int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
+               LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
+
 #endif
 
 #endif /* WINPR_CRT_STRING_H */
index 4e33666..b640531 100644 (file)
@@ -285,4 +285,219 @@ BOOL IsCharLowerW(WCHAR ch)
        return 0;
 }
 
+/*
+ * Advanced String Techniques in C++ - Part I: Unicode
+ * http://www.flipcode.com/archives/Advanced_String_Techniques_in_C-Part_I_Unicode.shtml
+ */
+
+/*
+ * Conversion *to* Unicode
+ * MultiByteToWideChar: http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072/
+ */
+
+int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
+               int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
+{
+       size_t ibl;
+       size_t obl;
+       char* pin;
+       char* pout;
+       char* pout0;
+
+       if (lpMultiByteStr == NULL)
+               return 0;
+
+       if (cbMultiByte < 0)
+               cbMultiByte = strlen(lpMultiByteStr) + 1;
+
+       ibl = cbMultiByte;
+       obl = 2 * ibl;
+
+       if (cchWideChar < 1)
+               return (obl / 2);
+
+       pin = (char*) lpMultiByteStr;
+       pout0 = (char*) lpWideCharStr;
+       pout = pout0;
+
+#ifdef HAVE_ICONV
+       {
+               iconv_t* out_iconv_h;
+
+               out_iconv_h = iconv_open(WINDOWS_CODEPAGE, DEFAULT_CODEPAGE);
+
+               if (errno == EINVAL)
+               {
+                       printf("Error opening iconv converter to %s from %s\n", WINDOWS_CODEPAGE, DEFAULT_CODEPAGE);
+                       return 0;
+               }
+
+               if (iconv(out_iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
+               {
+                       printf("MultiByteToWideChar: iconv() error\n");
+                       return NULL;
+               }
+
+               iconv_close(out_iconv_h);
+       }
+#else
+       while ((ibl > 0) && (obl > 0))
+       {
+               unsigned int wc;
+
+               wc = (unsigned int) (unsigned char) (*pin++);
+               ibl--;
+
+               if (wc >= 0xF0)
+               {
+                       wc = (wc - 0xF0) << 18;
+                       wc += ((unsigned int) (unsigned char) (*pin++) - 0x80) << 12;
+                       wc += ((unsigned int) (unsigned char) (*pin++) - 0x80) << 6;
+                       wc += ((unsigned int) (unsigned char) (*pin++) - 0x80);
+                       ibl -= 3;
+               }
+               else if (wc >= 0xE0)
+               {
+                       wc = (wc - 0xE0) << 12;
+                       wc += ((unsigned int) (unsigned char) (*pin++) - 0x80) << 6;
+                       wc += ((unsigned int) (unsigned char) (*pin++) - 0x80);
+                       ibl -= 2;
+               }
+               else if (wc >= 0xC0)
+               {
+                       wc = (wc - 0xC0) << 6;
+                       wc += ((unsigned int) (unsigned char) (*pin++) - 0x80);
+                       ibl -= 1;
+               }
+
+               if (wc <= 0xFFFF)
+               {
+                       *pout++ = (char) (wc & 0xFF);
+                       *pout++ = (char) (wc >> 8);
+                       obl -= 2;
+               }
+               else
+               {
+                       wc -= 0x10000;
+                       *pout++ = (char) ((wc >> 10) & 0xFF);
+                       *pout++ = (char) ((wc >> 18) + 0xD8);
+                       *pout++ = (char) (wc & 0xFF);
+                       *pout++ = (char) (((wc >> 8) & 0x03) + 0xDC);
+                       obl -= 4;
+               }
+       }
+#endif
+
+       if (ibl > 0)
+       {
+               printf("MultiByteToWideChar: string not fully converted - %d chars left\n", (int) ibl);
+               return 0;
+       }
+
+       return (pout - pout0) / 2;
+}
+
+/*
+ * Conversion *from* Unicode
+ * WideCharToMultiByte: http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130/
+ */
+
+int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
+               LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
+{
+       char* pout;
+       char* conv_pout;
+       size_t conv_in_len;
+       size_t conv_out_len;
+       unsigned char* conv_pin;
+
+       if (cchWideChar < 1)
+
+       if (cchWideChar == 0)
+               return 0;
+
+       conv_pin = (unsigned char*) lpWideCharStr;
+       conv_in_len = cchWideChar;
+       pout = lpMultiByteStr;
+       conv_pout = pout;
+       conv_out_len = cbMultiByte;
+
+#ifdef HAVE_ICONV
+       {
+               iconv_t* in_iconv_h;
+
+               in_iconv_h = iconv_open(DEFAULT_CODEPAGE, WINDOWS_CODEPAGE);
+
+               if (errno == EINVAL)
+               {
+                       printf("Error opening iconv converter to %s from %s\n", DEFAULT_CODEPAGE, WINDOWS_CODEPAGE);
+                       return 0;
+               }
+
+               if (iconv(in_iconv_h, (ICONV_CONST char **) &conv_pin, &conv_in_len, &conv_pout, &conv_out_len) == (size_t) - 1)
+               {
+                       printf("WideCharToMultiByte: iconv failure\n");
+                       return 0;
+               }
+
+               iconv_close(in_iconv_h);
+       }
+#else
+       while (conv_in_len >= 2)
+       {
+               unsigned int wc;
+
+               wc = (unsigned int) (unsigned char) (*conv_pin++);
+               wc += ((unsigned int) (unsigned char) (*conv_pin++)) << 8;
+               conv_in_len -= 2;
+
+               if (wc >= 0xD800 && wc <= 0xDFFF && conv_in_len >= 2)
+               {
+                       /* Code points U+10000 to U+10FFFF using surrogate pair */
+                       wc = ((wc - 0xD800) << 10) + 0x10000;
+                       wc += (unsigned int) (unsigned char) (*conv_pin++);
+                       wc += ((unsigned int) (unsigned char) (*conv_pin++) - 0xDC) << 8;
+                       conv_in_len -= 2;
+               }
+
+               if (wc <= 0x7F)
+               {
+                       *conv_pout++ = (char) wc;
+                       conv_out_len--;
+               }
+               else if (wc <= 0x07FF)
+               {
+                       *conv_pout++ = (char) (0xC0 + (wc >> 6));
+                       *conv_pout++ = (char) (0x80 + (wc & 0x3F));
+                       conv_out_len -= 2;
+               }
+               else if (wc <= 0xFFFF)
+               {
+                       *conv_pout++ = (char) (0xE0 + (wc >> 12));
+                       *conv_pout++ = (char) (0x80 + ((wc >> 6) & 0x3F));
+                       *conv_pout++ = (char) (0x80 + (wc & 0x3F));
+                       conv_out_len -= 3;
+               }
+               else
+               {
+                       *conv_pout++ = (char) (0xF0 + (wc >> 18));
+                       *conv_pout++ = (char) (0x80 + ((wc >> 12) & 0x3F));
+                       *conv_pout++ = (char) (0x80 + ((wc >> 6) & 0x3F));
+                       *conv_pout++ = (char) (0x80 + (wc & 0x3F));
+                       conv_out_len -= 4;
+               }
+       }
+#endif
+
+       if (conv_in_len > 0)
+       {
+               printf("WideCharToMultiByte: conversion failure - %d chars left\n", (int) conv_in_len);
+               return 0;
+       }
+
+       *conv_pout = 0;
+
+       return conv_out_len;
+}
+
 #endif
index 9e6b823..51e0d1f 100644 (file)
@@ -26,6 +26,7 @@
 #include <freerdp/crypto/tls.h>
 #include <freerdp/utils/stream.h>
 
+#include <winpr/crt.h>
 #include <winpr/sspi.h>
 #include <winpr/credssp.h>
 
 
 void credssp_SetContextIdentity(rdpCredssp* context, char* user, char* domain, char* password)
 {
-       size_t size;
        context->identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
 
-       context->identity.User = (uint16*) freerdp_uniconv_out(context->uniconv, user, &size);
-       context->identity.UserLength = (uint32) size;
+       context->identity.UserLength = strlen(user) * 2;
+       context->identity.User = (uint16*) malloc(context->identity.UserLength);
+       MultiByteToWideChar(CP_ACP, 0, user, strlen(user), (LPWSTR) context->identity.User, context->identity.UserLength / 2);
 
        if (domain)
        {
-               context->identity.Domain = (uint16*) freerdp_uniconv_out(context->uniconv, domain, &size);
-               context->identity.DomainLength = (uint32) size;
+               context->identity.DomainLength = strlen(user) * 2;
+               context->identity.Domain = (uint16*) malloc(context->identity.DomainLength);
+               MultiByteToWideChar(CP_ACP, 0, user, strlen(user), (LPWSTR) context->identity.Domain, context->identity.DomainLength / 2);
        }
        else
        {
@@ -96,8 +98,9 @@ void credssp_SetContextIdentity(rdpCredssp* context, char* user, char* domain, c
                context->identity.DomainLength = 0;
        }
 
-       context->identity.Password = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) password, &size);
-       context->identity.PasswordLength = (uint32) size;
+       context->identity.PasswordLength = strlen(password) * 2;
+       context->identity.Password = (uint16*) malloc(context->identity.PasswordLength);
+       MultiByteToWideChar(CP_ACP, 0, password, strlen(password), (LPWSTR) context->identity.Password, context->identity.PasswordLength / 2);
 }
 
 /**