1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/osx/core/strconv_cf.cpp 
   3 // Purpose:     Unicode conversion classes 
   4 // Author:      David Elliott 
   7 // Copyright:   (c) 2007 David Elliott 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  11 // For compilers that support precompilation, includes "wx.h". 
  12 #include "wx/wxprec.h" 
  15     #include "wx/string.h" 
  18 #include "wx/strconv.h" 
  19 #include "wx/fontmap.h" 
  23 #include "wx/osx/core/private/strconv_cf.h" 
  24 #include "wx/osx/core/cfref.h" 
  27 // ============================================================================ 
  28 // CoreFoundation conversion classes 
  29 // ============================================================================ 
  31 /* Provide factory functions for unit tests.  Not in any header.  Do not 
  32  * assume ABI compatibility even within a given wxWidgets release. 
  36 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_cf( const char* name
) 
  38     wxMBConv_cf 
*result 
= new wxMBConv_cf(name
); 
  47 #endif // wxUSE_FONTMAP 
  49 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_cf(wxFontEncoding encoding
) 
  51     wxMBConv_cf 
*result 
= new wxMBConv_cf(encoding
); 
  61 // Provide a constant for the wchat_t encoding used by the host platform. 
  62 #ifdef WORDS_BIGENDIAN 
  63     static const CFStringEncoding wxCFStringEncodingWcharT 
= kCFStringEncodingUTF32BE
; 
  65     static const CFStringEncoding wxCFStringEncodingWcharT 
= kCFStringEncodingUTF32LE
; 
  68     size_t wxMBConv_cf::ToWChar(wchar_t * dst
, size_t dstSize
, const char * src
, size_t srcSize
) const 
  70         wxCHECK(src
, wxCONV_FAILED
); 
  72         /* NOTE: This is wrong if the source encoding has an element size 
  73          * other than char (e.g. it's kCFStringEncodingUnicode) 
  74          * If the user specifies it, it's presumably right though. 
  75          * Right now we don't support UTF-16 in anyway since wx can do a better job. 
  77         if(srcSize 
== wxNO_LEN
) 
  78             srcSize 
= strlen(src
) + 1; 
  80         // First create the temporary CFString 
  81         wxCFRef
<CFStringRef
> theString( CFStringCreateWithBytes ( 
  86                                                 false //no BOM/external representation 
  89         if ( theString 
== NULL 
) 
  92         // Ensure that the string is in canonical composed form (NFC): this is 
  93         // important because Darwin uses decomposed form (NFD) for e.g. file 
  94         // names but we want to use NFC internally. 
  95         wxCFRef
<CFMutableStringRef
> 
  96             cfMutableString(CFStringCreateMutableCopy(NULL
, 0, theString
)); 
  97         CFStringNormalize(cfMutableString
, kCFStringNormalizationFormC
); 
  98         theString 
= cfMutableString
; 
 100         /* NOTE: The string content includes the NULL element if the source string did 
 101          * That means we have to do nothing special because the destination will have 
 102          * the NULL element iff the source did and the NULL element will be included 
 103          * in the count iff it was included in the source count. 
 107 /* If we're compiling against Tiger headers we can support direct conversion 
 108  * to UTF32.  If we are then run against a pre-Tiger system, the encoding 
 109  * won't be available so we'll defer to the string->UTF-16->UTF-32 conversion. 
 111         if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT
)) 
 113             CFRange fullStringRange 
= CFRangeMake(0, CFStringGetLength(theString
)); 
 116             CFIndex charsConverted 
= CFStringGetBytes( 
 119                     wxCFStringEncodingWcharT
, 
 122                     // if dstSize is 0 then pass NULL to get required length in usedBufLen 
 123                     dstSize 
!= 0?(UInt8
*)dst
:NULL
, 
 124                     dstSize 
* sizeof(wchar_t), 
 127             if(charsConverted 
< CFStringGetLength(theString
)) 
 128                 return wxCONV_FAILED
; 
 130             /* usedBufLen is the number of bytes written, so we divide by 
 131              * sizeof(wchar_t) to get the number of elements written. 
 133             wxASSERT( (usedBufLen 
% sizeof(wchar_t)) == 0 ); 
 135             // CFStringGetBytes does exactly the right thing when buffer 
 136             // pointer is NULL and returns the number of bytes required 
 137             return usedBufLen 
/ sizeof(wchar_t); 
 141             // NOTE: Includes NULL iff source did 
 142             /* NOTE: This is an approximation.  The eventual UTF-32 will 
 143              * possibly have less elements but certainly not more. 
 145             size_t returnSize 
= CFStringGetLength(theString
); 
 147             if (dstSize 
== 0 || dst 
== NULL
) 
 152             // Convert the entire string.. too hard to figure out how many UTF-16 we'd need 
 153             // for an undersized UTF-32 destination buffer. 
 154             CFRange fullStringRange 
= CFRangeMake(0, CFStringGetLength(theString
)); 
 155             UniChar 
*szUniCharBuffer 
= new UniChar
[fullStringRange
.length
]; 
 157             CFStringGetCharacters(theString
, fullStringRange
, szUniCharBuffer
); 
 159             wxMBConvUTF16 converter
; 
 160             returnSize 
= converter
.ToWChar( dst
, dstSize
, (const char*)szUniCharBuffer
, fullStringRange
.length 
); 
 161             delete [] szUniCharBuffer
; 
 168     size_t wxMBConv_cf::FromWChar(char *dst
, size_t dstSize
, const wchar_t *src
, size_t srcSize
) const 
 170         wxCHECK(src
, wxCONV_FAILED
); 
 172         if(srcSize 
== wxNO_LEN
) 
 173             srcSize 
= wxStrlen(src
) + 1; 
 175         // Temporary CFString 
 176         wxCFRef
<CFStringRef
> theString
; 
 178 /* If we're compiling against Tiger headers we can support direct conversion 
 179  * from UTF32.  If we are then run against a pre-Tiger system, the encoding 
 180  * won't be available so we'll defer to the UTF-32->UTF-16->string conversion. 
 182         if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT
)) 
 184             theString 
= wxCFRef
<CFStringRef
>(CFStringCreateWithBytes( 
 187                     srcSize 
* sizeof(wchar_t), 
 188                     wxCFStringEncodingWcharT
, 
 193             wxMBConvUTF16 converter
; 
 194             size_t cbUniBuffer 
= converter
.FromWChar( NULL
, 0, src
, srcSize 
); 
 195             wxASSERT(cbUniBuffer 
% sizeof(UniChar
)); 
 197             // Will be free'd by kCFAllocatorMalloc when CFString is released 
 198             UniChar 
*tmpUniBuffer 
= (UniChar
*)malloc(cbUniBuffer
); 
 200             cbUniBuffer 
= converter
.FromWChar( (char*) tmpUniBuffer
, cbUniBuffer
, src
, srcSize 
); 
 201             wxASSERT(cbUniBuffer 
% sizeof(UniChar
)); 
 203             theString 
= wxCFRef
<CFStringRef
>(CFStringCreateWithCharactersNoCopy( 
 206                         cbUniBuffer 
/ sizeof(UniChar
), 
 212         wxCHECK(theString 
!= NULL
, wxCONV_FAILED
); 
 216         CFIndex charsConverted 
= CFStringGetBytes( 
 218                 CFRangeMake(0, CFStringGetLength(theString
)), 
 220                 0, // FAIL on unconvertible characters 
 221                 false, // not an external representation 
 227         // when dst is non-NULL, we check usedBufLen against dstSize as 
 228         // CFStringGetBytes sometimes treats dst as being NULL when dstSize==0 
 229         if( (charsConverted 
< CFStringGetLength(theString
)) || 
 230                 (dst 
&& (size_t) usedBufLen 
> dstSize
) ) 
 231             return wxCONV_FAILED
;