]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/ustr_wcs.c
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / common / ustr_wcs.c
1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 2001-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 * file name: ustr_wcs.c
9 * encoding: US-ASCII
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * created on: 2004sep07
14 * created by: Markus W. Scherer
15 *
16 * u_strToWCS() and u_strFromWCS() functions
17 * moved here from ustrtrns.c for better modularization.
18 */
19
20 #include "unicode/utypes.h"
21 #include "unicode/ustring.h"
22 #include "cstring.h"
23 #include "cwchar.h"
24 #include "cmemory.h"
25 #include "ustr_imp.h"
26 #include "ustr_cnv.h"
27
28 #if defined(U_WCHAR_IS_UTF16) || defined(U_WCHAR_IS_UTF32) || !UCONFIG_NO_CONVERSION
29
30 #define _STACK_BUFFER_CAPACITY 1000
31 #define _BUFFER_CAPACITY_MULTIPLIER 2
32
33 #if !defined(U_WCHAR_IS_UTF16) && !defined(U_WCHAR_IS_UTF32)
34 static U_INLINE UBool
35 u_growAnyBufferFromStatic(void *context,
36 void **pBuffer, int32_t *pCapacity, int32_t reqCapacity,
37 int32_t length, int32_t size) {
38
39 void *newBuffer=uprv_malloc(reqCapacity*size);
40 if(newBuffer!=NULL) {
41 if(length>0) {
42 uprv_memcpy(newBuffer, *pBuffer, length*size);
43 }
44 *pCapacity=reqCapacity;
45 } else {
46 *pCapacity=0;
47 }
48
49 /* release the old pBuffer if it was not statically allocated */
50 if(*pBuffer!=(void *)context) {
51 uprv_free(*pBuffer);
52 }
53
54 *pBuffer=newBuffer;
55 return (UBool)(newBuffer!=NULL);
56 }
57
58 /* helper function */
59 static wchar_t*
60 _strToWCS(wchar_t *dest,
61 int32_t destCapacity,
62 int32_t *pDestLength,
63 const UChar *src,
64 int32_t srcLength,
65 UErrorCode *pErrorCode){
66
67 char stackBuffer [_STACK_BUFFER_CAPACITY];
68 char* tempBuf = stackBuffer;
69 int32_t tempBufCapacity = _STACK_BUFFER_CAPACITY;
70 char* tempBufLimit = stackBuffer + tempBufCapacity;
71 UConverter* conv = NULL;
72 char* saveBuf = tempBuf;
73 wchar_t* intTarget=NULL;
74 int32_t intTargetCapacity=0;
75 int count=0,retVal=0;
76
77 const UChar *pSrcLimit =NULL;
78 const UChar *pSrc = src;
79
80 conv = u_getDefaultConverter(pErrorCode);
81
82 if(U_FAILURE(*pErrorCode)){
83 return NULL;
84 }
85
86 if(srcLength == -1){
87 srcLength = u_strlen(pSrc);
88 }
89
90 pSrcLimit = pSrc + srcLength;
91
92 for(;;) {
93 /* reset the error state */
94 *pErrorCode = U_ZERO_ERROR;
95
96 /* convert to chars using default converter */
97 ucnv_fromUnicode(conv,&tempBuf,tempBufLimit,&pSrc,pSrcLimit,NULL,(UBool)(pSrc==pSrcLimit),pErrorCode);
98 count =(tempBuf - saveBuf);
99
100 /* This should rarely occur */
101 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR){
102 tempBuf = saveBuf;
103
104 /* we dont have enough room on the stack grow the buffer */
105 if(!u_growAnyBufferFromStatic(stackBuffer,(void**) &tempBuf, &tempBufCapacity,
106 (_BUFFER_CAPACITY_MULTIPLIER * (srcLength)), count,sizeof(char))){
107 goto cleanup;
108 }
109
110 saveBuf = tempBuf;
111 tempBufLimit = tempBuf + tempBufCapacity;
112 tempBuf = tempBuf + count;
113
114 } else {
115 break;
116 }
117 }
118
119 if(U_FAILURE(*pErrorCode)){
120 goto cleanup;
121 }
122
123 /* done with conversion null terminate the char buffer */
124 if(count>=tempBufCapacity){
125 tempBuf = saveBuf;
126 /* we dont have enough room on the stack grow the buffer */
127 if(!u_growAnyBufferFromStatic(stackBuffer,(void**) &tempBuf, &tempBufCapacity,
128 tempBufCapacity-count+1, count,sizeof(char))){
129 goto cleanup;
130 }
131 saveBuf = tempBuf;
132 }
133
134 saveBuf[count]=0;
135
136
137 /* allocate more space than required
138 * here we assume that every char requires
139 * no more than 2 wchar_ts
140 */
141 intTargetCapacity = (count * _BUFFER_CAPACITY_MULTIPLIER + 1) /*for null termination */;
142 intTarget = (wchar_t*)uprv_malloc( intTargetCapacity * sizeof(wchar_t) );
143
144 if(intTarget){
145
146 int32_t nulLen = 0;
147 int32_t remaining = intTargetCapacity;
148 wchar_t* pIntTarget=intTarget;
149 tempBuf = saveBuf;
150
151 /* now convert the mbs to wcs */
152 for(;;){
153
154 /* we can call the system API since we are sure that
155 * there is atleast 1 null in the input
156 */
157 retVal = uprv_mbstowcs(pIntTarget,(tempBuf+nulLen),remaining);
158
159 if(retVal==-1){
160 *pErrorCode = U_INVALID_CHAR_FOUND;
161 break;
162 }else if(retVal== remaining){/* should never occur */
163 int numWritten = (pIntTarget-intTarget);
164 u_growAnyBufferFromStatic(NULL,(void**) &intTarget,
165 &intTargetCapacity,
166 intTargetCapacity * _BUFFER_CAPACITY_MULTIPLIER,
167 numWritten,
168 sizeof(wchar_t));
169 pIntTarget = intTarget;
170 remaining=intTargetCapacity;
171
172 if(nulLen!=count){ /*there are embedded nulls*/
173 pIntTarget+=numWritten;
174 remaining-=numWritten;
175 }
176
177 }else{
178 int32_t nulVal;
179 /*scan for nulls */
180 /* we donot check for limit since tempBuf is null terminated */
181 while(tempBuf[nulLen++] != 0){
182 }
183 nulVal = (nulLen < srcLength) ? 1 : 0;
184 pIntTarget = pIntTarget + retVal+nulVal;
185 remaining -=(retVal+nulVal);
186
187 /* check if we have reached the source limit*/
188 if(nulLen>=(count)){
189 break;
190 }
191 }
192 }
193 count = (int32_t)(pIntTarget-intTarget);
194
195 if(0 < count && count <= destCapacity){
196 uprv_memcpy(dest,intTarget,count*sizeof(wchar_t));
197 }
198
199 if(pDestLength){
200 *pDestLength = count;
201 }
202
203 /* free the allocated memory */
204 uprv_free(intTarget);
205
206 }else{
207 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
208 }
209 cleanup:
210 /* are we still using stack buffer */
211 if(stackBuffer != saveBuf){
212 uprv_free(saveBuf);
213 }
214 u_terminateWChars(dest,destCapacity,count,pErrorCode);
215
216 u_releaseDefaultConverter(conv);
217
218 return dest;
219 }
220 #endif
221
222 U_CAPI wchar_t* U_EXPORT2
223 u_strToWCS(wchar_t *dest,
224 int32_t destCapacity,
225 int32_t *pDestLength,
226 const UChar *src,
227 int32_t srcLength,
228 UErrorCode *pErrorCode){
229
230 /* args check */
231 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)){
232 return NULL;
233 }
234
235 if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
236 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
237 return NULL;
238 }
239
240 #ifdef U_WCHAR_IS_UTF16
241 /* wchar_t is UTF-16 just do a memcpy */
242 if(srcLength == -1){
243 srcLength = u_strlen(src);
244 }
245 if(0 < srcLength && srcLength <= destCapacity){
246 uprv_memcpy(dest,src,srcLength*U_SIZEOF_UCHAR);
247 }
248 if(pDestLength){
249 *pDestLength = srcLength;
250 }
251
252 u_terminateUChars(dest,destCapacity,srcLength,pErrorCode);
253
254 return dest;
255
256 #elif defined U_WCHAR_IS_UTF32
257
258 return (wchar_t*)u_strToUTF32((UChar32*)dest, destCapacity, pDestLength,
259 src, srcLength, pErrorCode);
260
261 #else
262
263 return _strToWCS(dest,destCapacity,pDestLength,src,srcLength, pErrorCode);
264
265 #endif
266
267 }
268
269 #if !defined(U_WCHAR_IS_UTF16) && !defined(U_WCHAR_IS_UTF32)
270 /* helper function */
271 static UChar*
272 _strFromWCS( UChar *dest,
273 int32_t destCapacity,
274 int32_t *pDestLength,
275 const wchar_t *src,
276 int32_t srcLength,
277 UErrorCode *pErrorCode)
278 {
279 int32_t retVal =0, count =0 ;
280 UConverter* conv = NULL;
281 UChar* pTarget = NULL;
282 UChar* pTargetLimit = NULL;
283 UChar* target = NULL;
284
285 UChar uStack [_STACK_BUFFER_CAPACITY];
286
287 wchar_t wStack[_STACK_BUFFER_CAPACITY];
288 wchar_t* pWStack = wStack;
289
290
291 char cStack[_STACK_BUFFER_CAPACITY];
292 int32_t cStackCap = _STACK_BUFFER_CAPACITY;
293 char* pCSrc=cStack;
294 char* pCSave=pCSrc;
295 char* pCSrcLimit=NULL;
296
297 const wchar_t* pSrc = src;
298 const wchar_t* pSrcLimit = NULL;
299
300 if(srcLength ==-1){
301 /* if the wchar_t source is null terminated we can safely
302 * assume that there are no embedded nulls, this is a fast
303 * path for null terminated strings.
304 */
305 for(;;){
306 /* convert wchars to chars */
307 retVal = uprv_wcstombs(pCSrc,src, cStackCap);
308
309 if(retVal == -1){
310 *pErrorCode = U_ILLEGAL_CHAR_FOUND;
311 goto cleanup;
312 }else if(retVal >= (cStackCap-1)){
313 /* Should rarely occur */
314 u_growAnyBufferFromStatic(cStack,(void**)&pCSrc,&cStackCap,
315 cStackCap * _BUFFER_CAPACITY_MULTIPLIER, 0, sizeof(char));
316 pCSave = pCSrc;
317 }else{
318 /* converted every thing */
319 pCSrc = pCSrc+retVal;
320 break;
321 }
322 }
323
324 }else{
325 /* here the source is not null terminated
326 * so it may have nulls embeded and we need to
327 * do some extra processing
328 */
329 int32_t remaining =cStackCap;
330
331 pSrcLimit = src + srcLength;
332
333 for(;;){
334 register int32_t nulLen = 0;
335
336 /* find nulls in the string */
337 while(nulLen<srcLength && pSrc[nulLen++]!=0){
338 }
339
340 if((pSrc+nulLen) < pSrcLimit){
341 /* check if we have enough room in pCSrc */
342 if(remaining < (nulLen * MB_CUR_MAX)){
343 /* should rarely occur */
344 int32_t len = (pCSrc-pCSave);
345 pCSrc = pCSave;
346 /* we do not have enough room so grow the buffer*/
347 u_growAnyBufferFromStatic(cStack,(void**)&pCSrc,&cStackCap,
348 _BUFFER_CAPACITY_MULTIPLIER*cStackCap+(nulLen*MB_CUR_MAX),len,sizeof(char));
349
350 pCSave = pCSrc;
351 pCSrc = pCSave+len;
352 remaining = cStackCap-(pCSrc - pCSave);
353 }
354
355 /* we have found a null so convert the
356 * chunk from begining of non-null char to null
357 */
358 retVal = uprv_wcstombs(pCSrc,pSrc,remaining);
359
360 if(retVal==-1){
361 /* an error occurred bail out */
362 *pErrorCode = U_ILLEGAL_CHAR_FOUND;
363 goto cleanup;
364 }
365
366 pCSrc += retVal+1 /* already null terminated */;
367
368 pSrc += nulLen; /* skip past the null */
369 srcLength-=nulLen; /* decrement the srcLength */
370 remaining -= (pCSrc-pCSave);
371
372
373 }else{
374 /* the source is not null terminated and we are
375 * end of source so we copy the source to a temp buffer
376 * null terminate it and convert wchar_ts to chars
377 */
378 if(nulLen >= _STACK_BUFFER_CAPACITY){
379 /* Should rarely occcur */
380 /* allocate new buffer buffer */
381 pWStack =(wchar_t*) uprv_malloc(sizeof(wchar_t) * (nulLen + 1));
382 if(pWStack==NULL){
383 *pErrorCode = U_MEMORY_ALLOCATION_ERROR;
384 goto cleanup;
385 }
386 }
387 if(nulLen>0){
388 /* copy the contents to tempStack */
389 uprv_memcpy(pWStack,pSrc,nulLen*sizeof(wchar_t));
390 }
391
392 /* null terminate the tempBuffer */
393 pWStack[nulLen] =0 ;
394
395 if(remaining < (nulLen * MB_CUR_MAX)){
396 /* Should rarely occur */
397 int32_t len = (pCSrc-pCSave);
398 pCSrc = pCSave;
399 /* we do not have enough room so grow the buffer*/
400 u_growAnyBufferFromStatic(cStack,(void**)&pCSrc,&cStackCap,
401 cStackCap+(nulLen*MB_CUR_MAX),len,sizeof(char));
402
403 pCSave = pCSrc;
404 pCSrc = pCSave+len;
405 remaining = cStackCap-(pCSrc - pCSave);
406 }
407 /* convert to chars */
408 retVal = uprv_wcstombs(pCSrc,pWStack,remaining);
409
410 pCSrc += retVal;
411 pSrc += nulLen;
412 srcLength-=nulLen; /* decrement the srcLength */
413 break;
414 }
415 }
416 }
417
418 /* OK..now we have converted from wchar_ts to chars now
419 * convert chars to UChars
420 */
421 pCSrcLimit = pCSrc;
422 pCSrc = pCSave;
423 pTarget = target= dest;
424 pTargetLimit = dest + destCapacity;
425
426 conv= u_getDefaultConverter(pErrorCode);
427
428 if(U_FAILURE(*pErrorCode)|| conv==NULL){
429 goto cleanup;
430 }
431
432 for(;;) {
433
434 *pErrorCode = U_ZERO_ERROR;
435
436 /* convert to stack buffer*/
437 ucnv_toUnicode(conv,&pTarget,pTargetLimit,(const char**)&pCSrc,pCSrcLimit,NULL,(UBool)(pCSrc==pCSrcLimit),pErrorCode);
438
439 /* increment count to number written to stack */
440 count+= pTarget - target;
441
442 if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR){
443 target = uStack;
444 pTarget = uStack;
445 pTargetLimit = uStack + _STACK_BUFFER_CAPACITY;
446 } else {
447 break;
448 }
449
450 }
451
452 if(pDestLength){
453 *pDestLength =count;
454 }
455
456 u_terminateUChars(dest,destCapacity,count,pErrorCode);
457
458 cleanup:
459
460 if(cStack != pCSave){
461 uprv_free(pCSave);
462 }
463
464 if(wStack != pWStack){
465 uprv_free(pWStack);
466 }
467
468 u_releaseDefaultConverter(conv);
469
470 return dest;
471 }
472 #endif
473
474 U_CAPI UChar* U_EXPORT2
475 u_strFromWCS(UChar *dest,
476 int32_t destCapacity,
477 int32_t *pDestLength,
478 const wchar_t *src,
479 int32_t srcLength,
480 UErrorCode *pErrorCode)
481 {
482
483 /* args check */
484 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)){
485 return NULL;
486 }
487
488 if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
489 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
490 return NULL;
491 }
492
493 #ifdef U_WCHAR_IS_UTF16
494 /* wchar_t is UTF-16 just do a memcpy */
495 if(srcLength == -1){
496 srcLength = u_strlen(src);
497 }
498 if(0 < srcLength && srcLength <= destCapacity){
499 uprv_memcpy(dest,src,srcLength*U_SIZEOF_UCHAR);
500 }
501 if(pDestLength){
502 *pDestLength = srcLength;
503 }
504
505 u_terminateUChars(dest,destCapacity,srcLength,pErrorCode);
506
507 return dest;
508
509 #elif defined U_WCHAR_IS_UTF32
510
511 return u_strFromUTF32(dest, destCapacity, pDestLength,
512 (UChar32*)src, srcLength, pErrorCode);
513
514 #else
515
516 return _strFromWCS(dest,destCapacity,pDestLength,src,srcLength,pErrorCode);
517
518 #endif
519
520 }
521
522 #endif /* #if !defined(U_WCHAR_IS_UTF16) && !defined(U_WCHAR_IS_UTF32) && !UCONFIG_NO_CONVERSION */