1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/corefoundation/strconv.cpp 
   3 // Purpose:     Unicode conversion classes 
   4 // Author:      David Elliott 
   8 // Copyright:   (c) 2007 David Elliott 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  16     #include "wx/string.h" 
  19 #include "wx/strconv.h" 
  20 #include "wx/fontmap.h" 
  24 #include "wx/mac/corefoundation/private/strconv_cf.h" 
  25 #include "wx/mac/corefoundation/cfref.h" 
  28 // ============================================================================ 
  29 // CoreFoundation conversion classes 
  30 // ============================================================================ 
  32 /* Provide factory functions for unit tests.  Not in any header.  Do not 
  33  * 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
); 
  48 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_cf(wxFontEncoding encoding
) 
  50     wxMBConv_cf 
*result 
= new wxMBConv_cf(encoding
); 
  60 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 
  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 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ 
  70     size_t wxMBConv_cf::ToWChar(wchar_t * dst
, size_t dstSize
, const char * src
, size_t srcSize
) const 
  72         wxCHECK(src
, wxCONV_FAILED
); 
  74         /* NOTE: This is wrong if the source encoding has an element size 
  75          * other than char (e.g. it's kCFStringEncodingUnicode) 
  76          * If the user specifies it, it's presumably right though. 
  77          * Right now we don't support UTF-16 in anyway since wx can do a better job. 
  79         if(srcSize 
== wxNO_LEN
) 
  80             srcSize 
= strlen(src
) + 1; 
  82         // First create the temporary CFString 
  83         wxCFRef
<CFStringRef
> theString( CFStringCreateWithBytes ( 
  88                                                 false //no BOM/external representation 
  91         wxCHECK(theString 
!= NULL
, wxCONV_FAILED
); 
  93         /* NOTE: The string content includes the NULL element if the source string did 
  94          * That means we have to do nothing special because the destination will have 
  95          * the NULL element iff the source did and the NULL element will be included 
  96          * in the count iff it was included in the source count. 
 100 /* If we're compiling against Tiger headers we can support direct conversion 
 101  * to UTF32.  If we are then run against a pre-Tiger system, the encoding 
 102  * won't be available so we'll defer to the string->UTF-16->UTF-32 conversion. 
 104 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 
 105         if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT
)) 
 107             CFRange fullStringRange 
= CFRangeMake(0, CFStringGetLength(theString
)); 
 110             CFIndex charsConverted 
= CFStringGetBytes( 
 113                     wxCFStringEncodingWcharT
, 
 116                     // if dstSize is 0 then pass NULL to get required length in usedBufLen 
 117                     dstSize 
!= 0?(UInt8
*)dst
:NULL
, 
 118                     dstSize 
* sizeof(wchar_t), 
 121             // charsConverted is > 0 iff conversion succeeded 
 122             if(charsConverted 
<= 0) 
 123                 return wxCONV_FAILED
; 
 125             /* usedBufLen is the number of bytes written, so we divide by 
 126              * sizeof(wchar_t) to get the number of elements written. 
 128             wxASSERT( (usedBufLen 
% sizeof(wchar_t)) == 0 ); 
 130             // CFStringGetBytes does exactly the right thing when buffer 
 131             // pointer is NULL and returns the number of bytes required 
 132             return usedBufLen 
/ sizeof(wchar_t); 
 135 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ 
 137             // NOTE: Includes NULL iff source did 
 138             /* NOTE: This is an approximation.  The eventual UTF-32 will     
 139              * possibly have less elements but certainly not more. 
 141             size_t returnSize 
= CFStringGetLength(theString
); 
 143             if (dstSize 
== 0 || dst 
== NULL
) 
 148             // Convert the entire string.. too hard to figure out how many UTF-16 we'd need 
 149             // for an undersized UTF-32 destination buffer. 
 150             CFRange fullStringRange 
= CFRangeMake(0, CFStringGetLength(theString
)); 
 151             UniChar 
*szUniCharBuffer 
= new UniChar
[fullStringRange
.length
]; 
 153             CFStringGetCharacters(theString
, fullStringRange
, szUniCharBuffer
); 
 155             wxMBConvUTF16 converter
; 
 156             returnSize 
= converter
.ToWChar( dst
, dstSize
, (const char*)szUniCharBuffer
, fullStringRange
.length 
); 
 157             delete [] szUniCharBuffer
; 
 164     size_t wxMBConv_cf::FromWChar(char *dst
, size_t dstSize
, const wchar_t *src
, size_t srcSize
) const 
 166         wxCHECK(src
, wxCONV_FAILED
); 
 168         if(srcSize 
== wxNO_LEN
) 
 169             srcSize 
= wxStrlen(src
) + 1; 
 171         // Temporary CFString 
 172         wxCFRef
<CFStringRef
> theString
; 
 174 /* If we're compiling against Tiger headers we can support direct conversion 
 175  * from UTF32.  If we are then run against a pre-Tiger system, the encoding 
 176  * won't be available so we'll defer to the UTF-32->UTF-16->string conversion. 
 178 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 
 179         if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT
)) 
 181             theString 
= wxCFRef
<CFStringRef
>(CFStringCreateWithBytes( 
 184                     srcSize 
* sizeof(wchar_t), 
 185                     wxCFStringEncodingWcharT
, 
 189 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ 
 191             wxMBConvUTF16 converter
; 
 192             size_t cbUniBuffer 
= converter
.FromWChar( NULL
, 0, src
, srcSize 
); 
 193             wxASSERT(cbUniBuffer 
% sizeof(UniChar
)); 
 195             // Will be free'd by kCFAllocatorMalloc when CFString is released 
 196             UniChar 
*tmpUniBuffer 
= (UniChar
*)malloc(cbUniBuffer
); 
 198             cbUniBuffer 
= converter
.FromWChar( (char*) tmpUniBuffer
, cbUniBuffer
, src
, srcSize 
); 
 199             wxASSERT(cbUniBuffer 
% sizeof(UniChar
)); 
 201             theString 
= wxCFRef
<CFStringRef
>(CFStringCreateWithCharactersNoCopy( 
 204                         cbUniBuffer 
/ sizeof(UniChar
), 
 210         wxCHECK(theString 
!= NULL
, wxCONV_FAILED
); 
 214         CFIndex charsConverted 
= CFStringGetBytes( 
 216                 CFRangeMake(0, CFStringGetLength(theString
)), 
 218                 0, // FAIL on unconvertible characters 
 219                 false, // not an external representation 
 220                 // if dstSize is 0 then pass NULL to get required length in usedBufLen 
 221                 (dstSize 
!= 0)?(UInt8
*)dst
:NULL
, 
 226         // charsConverted is > 0 iff conversion succeeded 
 227         if(charsConverted 
<= 0) 
 228             return wxCONV_FAILED
;