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