Piotr Caban : kernel32: Added IdnToNameprepUnicode implementation.

Alexandre Julliard julliard at winehq.org
Thu Apr 26 13:58:36 CDT 2012


Module: wine
Branch: master
Commit: a08710f3d042ecc950723c8bdbd4b34b71dbbe9f
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=a08710f3d042ecc950723c8bdbd4b34b71dbbe9f

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Tue Apr 24 16:10:53 2012 +0200

kernel32: Added IdnToNameprepUnicode implementation.

---

 dlls/kernel32/locale.c |  174 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 171 insertions(+), 3 deletions(-)

diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 20451ff..02a351c 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -172,6 +172,10 @@ static inline void strcpynAtoW( WCHAR *dst, const char *src, size_t n )
     if (n) *dst = 0;
 }
 
+static inline unsigned short get_table_entry( const unsigned short *table, WCHAR ch )
+{
+    return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)];
+}
 
 /***********************************************************************
  *		get_lcid_codepage
@@ -3895,10 +3899,174 @@ INT WINAPI IdnToAscii(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeCha
 INT WINAPI IdnToNameprepUnicode(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeChar,
                                 LPWSTR lpNameprepCharStr, INT cchNameprepChar)
 {
-    FIXME("%x %p %d %p %d\n", dwFlags, lpUnicodeCharStr, cchUnicodeChar,
+    enum {
+        UNASSIGNED = 0x1,
+        PROHIBITED = 0x2,
+        BIDI_RAL   = 0x4,
+        BIDI_L     = 0x8
+    };
+
+    extern const unsigned short nameprep_char_type[];
+    extern const WCHAR nameprep_mapping[];
+    const WCHAR *ptr;
+    WORD flags;
+    WCHAR *map_str, *norm_str, ch;
+    DWORD i, map_len, norm_len, mask;
+    BOOL have_bidi_ral = FALSE, prohibit_bidi_ral = FALSE, ascii_only = TRUE;
+
+    TRACE("%x %p %d %p %d\n", dwFlags, lpUnicodeCharStr, cchUnicodeChar,
         lpNameprepCharStr, cchNameprepChar);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return 0;
+
+    if(dwFlags & ~(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES)) {
+        SetLastError(ERROR_INVALID_FLAGS);
+        return 0;
+    }
+
+    if(!lpUnicodeCharStr || cchUnicodeChar<-1) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+
+    if(cchUnicodeChar == -1)
+        cchUnicodeChar = strlenW(lpUnicodeCharStr)+1;
+    if(!cchUnicodeChar || (cchUnicodeChar==1 && lpUnicodeCharStr[0]==0)) {
+        SetLastError(ERROR_INVALID_NAME);
+        return 0;
+    }
+
+    for(i=0; i<cchUnicodeChar; i++) {
+        ch = lpUnicodeCharStr[i];
+        if(ch > 0x8f) {
+            ascii_only = FALSE;
+            continue;
+        }
+
+        if(i==cchUnicodeChar-1 && !ch)
+            continue;
+        if(!ch) {
+            SetLastError(ERROR_INVALID_NAME);
+            return 0;
+        }
+
+        if((dwFlags&IDN_USE_STD3_ASCII_RULES) == 0)
+            continue;
+        if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z')
+                || (ch>='0' && ch<='9') || ch=='-')
+            continue;
+
+        SetLastError(ERROR_INVALID_NAME);
+        return 0;
+    }
+
+    if((dwFlags&IDN_USE_STD3_ASCII_RULES) &&
+            (lpUnicodeCharStr[0]=='-' || lpUnicodeCharStr[cchUnicodeChar-1]=='-' ||
+             (cchUnicodeChar>1 && lpUnicodeCharStr[cchUnicodeChar-1]==0 &&
+              lpUnicodeCharStr[cchUnicodeChar-2]=='-'))) {
+        SetLastError(ERROR_INVALID_NAME);
+        return 0;
+    }
+
+    if(ascii_only) {
+        if(!lpNameprepCharStr)
+            return cchUnicodeChar;
+        if(cchNameprepChar < cchUnicodeChar) {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            return 0;
+        }
+        memcpy(lpNameprepCharStr, lpUnicodeCharStr, cchUnicodeChar*sizeof(WCHAR));
+        return cchUnicodeChar;
+    }
+
+    map_len = 0;
+    for(i=0; i<cchUnicodeChar; i++) {
+        ch = lpUnicodeCharStr[i];
+        ptr = nameprep_mapping + nameprep_mapping[ch>>8];
+        ptr = nameprep_mapping + ptr[(ch>>4)&0x0f] + 3*(ch&0x0f);
+
+        if(!ptr[0]) map_len++;
+        else if(!ptr[1]) map_len++;
+        else if(!ptr[2]) map_len += 2;
+        else if(ptr[0]!=0xffff || ptr[1]!=0xffff || ptr[2]!=0xffff) map_len += 3;
+    }
+    map_str = HeapAlloc(GetProcessHeap(), 0, map_len*sizeof(WCHAR));
+    if(!map_str) {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;
+    }
+    map_len = 0;
+    for(i=0; i<cchUnicodeChar; i++) {
+        ch = lpUnicodeCharStr[i];
+        ptr = nameprep_mapping + nameprep_mapping[ch>>8];
+        ptr = nameprep_mapping + ptr[(ch>>4)&0x0f] + 3*(ch&0x0f);
+
+        if(!ptr[0]) {
+            map_str[map_len++] = ch;
+        }else if(!ptr[1]) {
+            map_str[map_len++] = ptr[0];
+        }else if(!ptr[2]) {
+            map_str[map_len++] = ptr[0];
+            map_str[map_len++] = ptr[1];
+        }else if(ptr[0]!=0xffff || ptr[1]!=0xffff || ptr[2]!=0xffff) {
+            map_str[map_len++] = ptr[0];
+            map_str[map_len++] = ptr[1];
+            map_str[map_len++] = ptr[2];
+        }
+    }
+
+    norm_len = FoldStringW(MAP_FOLDCZONE, map_str, map_len, lpNameprepCharStr, cchNameprepChar);
+    if(lpNameprepCharStr) {
+        norm_str = lpNameprepCharStr;
+    }else {
+        norm_str = HeapAlloc(GetProcessHeap(), 0, norm_len*sizeof(WCHAR));
+        if(!norm_str) {
+            HeapFree(GetProcessHeap(), 0, map_str);
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return 0;
+        }
+        FoldStringW(MAP_FOLDCZONE, map_str, map_len, norm_str, norm_len);
+    }
+    HeapFree(GetProcessHeap(), 0, map_str);
+
+    mask = PROHIBITED;
+    if((dwFlags&IDN_ALLOW_UNASSIGNED) == 0)
+        mask |= UNASSIGNED;
+    for(i=0; i<norm_len; i++) {
+        ch = norm_str[i];
+        flags = get_table_entry( nameprep_char_type, ch );
+
+        if(flags & mask) {
+            if(norm_str != lpNameprepCharStr)
+                HeapFree(GetProcessHeap(), 0, norm_str);
+            SetLastError((flags & PROHIBITED) ? ERROR_INVALID_NAME : ERROR_NO_UNICODE_TRANSLATION);
+            return 0;
+        }
+
+        if(flags & BIDI_RAL)
+            have_bidi_ral = TRUE;
+        if(flags & BIDI_L)
+            prohibit_bidi_ral = TRUE;
+    }
+
+    if(have_bidi_ral) {
+        ch = norm_str[0];
+        flags = get_table_entry( nameprep_char_type, ch );
+        if((flags & BIDI_RAL) == 0)
+            prohibit_bidi_ral = TRUE;
+
+        ch = norm_str[norm_len-1];
+        flags = get_table_entry( nameprep_char_type, ch );
+        if((flags & BIDI_RAL) == 0)
+            prohibit_bidi_ral = TRUE;
+    }
+
+    if(norm_str != lpNameprepCharStr)
+        HeapFree(GetProcessHeap(), 0, norm_str);
+
+    if(have_bidi_ral && prohibit_bidi_ral) {
+        SetLastError(ERROR_INVALID_NAME);
+        return 0;
+    }
+    return norm_len;
 }
 
 /******************************************************************************




More information about the wine-cvs mailing list