1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/core/strconv_cf.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/osx/core/private/strconv_cf.h"
25 #include "wx/osx/core/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.
37 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_cf( const char* name
)
39 wxMBConv_cf
*result
= new wxMBConv_cf(name
);
48 #endif // wxUSE_FONTMAP
50 WXDLLIMPEXP_BASE wxMBConv
* new_wxMBConv_cf(wxFontEncoding encoding
)
52 wxMBConv_cf
*result
= new wxMBConv_cf(encoding
);
62 // Provide a constant for the wchat_t encoding used by the host platform.
63 #ifdef WORDS_BIGENDIAN
64 static const CFStringEncoding wxCFStringEncodingWcharT
= kCFStringEncodingUTF32BE
;
66 static const CFStringEncoding wxCFStringEncodingWcharT
= kCFStringEncodingUTF32LE
;
69 size_t wxMBConv_cf::ToWChar(wchar_t * dst
, size_t dstSize
, const char * src
, size_t srcSize
) const
71 wxCHECK(src
, wxCONV_FAILED
);
73 /* NOTE: This is wrong if the source encoding has an element size
74 * other than char (e.g. it's kCFStringEncodingUnicode)
75 * If the user specifies it, it's presumably right though.
76 * Right now we don't support UTF-16 in anyway since wx can do a better job.
78 if(srcSize
== wxNO_LEN
)
79 srcSize
= strlen(src
) + 1;
81 // First create the temporary CFString
82 wxCFRef
<CFStringRef
> theString( CFStringCreateWithBytes (
87 false //no BOM/external representation
90 if ( theString
== NULL
)
93 // Ensure that the string is in canonical composed form (NFC): this is
94 // important because Darwin uses decomposed form (NFD) for e.g. file
95 // names but we want to use NFC internally.
96 wxCFRef
<CFMutableStringRef
>
97 cfMutableString(CFStringCreateMutableCopy(NULL
, 0, theString
));
98 CFStringNormalize(cfMutableString
, kCFStringNormalizationFormC
);
99 theString
= cfMutableString
;
101 /* NOTE: The string content includes the NULL element if the source string did
102 * That means we have to do nothing special because the destination will have
103 * the NULL element iff the source did and the NULL element will be included
104 * in the count iff it was included in the source count.
108 /* If we're compiling against Tiger headers we can support direct conversion
109 * to UTF32. If we are then run against a pre-Tiger system, the encoding
110 * won't be available so we'll defer to the string->UTF-16->UTF-32 conversion.
112 if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT
))
114 CFRange fullStringRange
= CFRangeMake(0, CFStringGetLength(theString
));
117 CFIndex charsConverted
= CFStringGetBytes(
120 wxCFStringEncodingWcharT
,
123 // if dstSize is 0 then pass NULL to get required length in usedBufLen
124 dstSize
!= 0?(UInt8
*)dst
:NULL
,
125 dstSize
* sizeof(wchar_t),
128 if(charsConverted
< CFStringGetLength(theString
))
129 return wxCONV_FAILED
;
131 /* usedBufLen is the number of bytes written, so we divide by
132 * sizeof(wchar_t) to get the number of elements written.
134 wxASSERT( (usedBufLen
% sizeof(wchar_t)) == 0 );
136 // CFStringGetBytes does exactly the right thing when buffer
137 // pointer is NULL and returns the number of bytes required
138 return usedBufLen
/ sizeof(wchar_t);
142 // NOTE: Includes NULL iff source did
143 /* NOTE: This is an approximation. The eventual UTF-32 will
144 * possibly have less elements but certainly not more.
146 size_t returnSize
= CFStringGetLength(theString
);
148 if (dstSize
== 0 || dst
== NULL
)
153 // Convert the entire string.. too hard to figure out how many UTF-16 we'd need
154 // for an undersized UTF-32 destination buffer.
155 CFRange fullStringRange
= CFRangeMake(0, CFStringGetLength(theString
));
156 UniChar
*szUniCharBuffer
= new UniChar
[fullStringRange
.length
];
158 CFStringGetCharacters(theString
, fullStringRange
, szUniCharBuffer
);
160 wxMBConvUTF16 converter
;
161 returnSize
= converter
.ToWChar( dst
, dstSize
, (const char*)szUniCharBuffer
, fullStringRange
.length
);
162 delete [] szUniCharBuffer
;
169 size_t wxMBConv_cf::FromWChar(char *dst
, size_t dstSize
, const wchar_t *src
, size_t srcSize
) const
171 wxCHECK(src
, wxCONV_FAILED
);
173 if(srcSize
== wxNO_LEN
)
174 srcSize
= wxStrlen(src
) + 1;
176 // Temporary CFString
177 wxCFRef
<CFStringRef
> theString
;
179 /* If we're compiling against Tiger headers we can support direct conversion
180 * from UTF32. If we are then run against a pre-Tiger system, the encoding
181 * won't be available so we'll defer to the UTF-32->UTF-16->string conversion.
183 if(CFStringIsEncodingAvailable(wxCFStringEncodingWcharT
))
185 theString
= wxCFRef
<CFStringRef
>(CFStringCreateWithBytes(
188 srcSize
* sizeof(wchar_t),
189 wxCFStringEncodingWcharT
,
194 wxMBConvUTF16 converter
;
195 size_t cbUniBuffer
= converter
.FromWChar( NULL
, 0, src
, srcSize
);
196 wxASSERT(cbUniBuffer
% sizeof(UniChar
));
198 // Will be free'd by kCFAllocatorMalloc when CFString is released
199 UniChar
*tmpUniBuffer
= (UniChar
*)malloc(cbUniBuffer
);
201 cbUniBuffer
= converter
.FromWChar( (char*) tmpUniBuffer
, cbUniBuffer
, src
, srcSize
);
202 wxASSERT(cbUniBuffer
% sizeof(UniChar
));
204 theString
= wxCFRef
<CFStringRef
>(CFStringCreateWithCharactersNoCopy(
207 cbUniBuffer
/ sizeof(UniChar
),
213 wxCHECK(theString
!= NULL
, wxCONV_FAILED
);
217 CFIndex charsConverted
= CFStringGetBytes(
219 CFRangeMake(0, CFStringGetLength(theString
)),
221 0, // FAIL on unconvertible characters
222 false, // not an external representation
228 // when dst is non-NULL, we check usedBufLen against dstSize as
229 // CFStringGetBytes sometimes treats dst as being NULL when dstSize==0
230 if( (charsConverted
< CFStringGetLength(theString
)) ||
231 (dst
&& (size_t) usedBufLen
> dstSize
) )
232 return wxCONV_FAILED
;