2 *******************************************************************************
4 * Copyright (C) 2003-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: usprep.cpp
10 * tab size: 8 (not used)
13 * created on: 2003jul2
14 * created by: Ram Viswanadha
17 #include "unicode/utypes.h"
21 #include "unicode/usprep.h"
23 #include "unicode/unorm.h"
24 #include "unicode/ustring.h"
25 #include "unicode/uchar.h"
26 #include "unicode/uversion.h"
36 #include "ubidi_props.h"
41 Static cache for already opened StringPrep profiles
43 static UHashtable
*SHARED_DATA_HASHTABLE
= NULL
;
45 static UMTX usprepMutex
= NULL
;
47 /* format version of spp file */
48 static uint8_t formatVersion
[4]={ 0, 0, 0, 0 };
50 /* the Unicode version of the sprep data */
51 static UVersionInfo dataVersion
={ 0, 0, 0, 0 };
53 static UBool U_CALLCONV
54 isSPrepAcceptable(void * /* context */,
55 const char * /* type */,
56 const char * /* name */,
57 const UDataInfo
*pInfo
) {
60 pInfo
->isBigEndian
==U_IS_BIG_ENDIAN
&&
61 pInfo
->charsetFamily
==U_CHARSET_FAMILY
&&
62 pInfo
->dataFormat
[0]==0x53 && /* dataFormat="SPRP" */
63 pInfo
->dataFormat
[1]==0x50 &&
64 pInfo
->dataFormat
[2]==0x52 &&
65 pInfo
->dataFormat
[3]==0x50 &&
66 pInfo
->formatVersion
[0]==3 &&
67 pInfo
->formatVersion
[2]==UTRIE_SHIFT
&&
68 pInfo
->formatVersion
[3]==UTRIE_INDEX_SHIFT
70 uprv_memcpy(formatVersion
, pInfo
->formatVersion
, 4);
71 uprv_memcpy(dataVersion
, pInfo
->dataVersion
, 4);
78 static int32_t U_CALLCONV
79 getSPrepFoldingOffset(uint32_t data
) {
86 static int32_t U_CALLCONV
87 hashEntry(const UHashTok parm
) {
88 UStringPrepKey
*b
= (UStringPrepKey
*)parm
.pointer
;
89 UHashTok namekey
, pathkey
;
90 namekey
.pointer
= b
->name
;
91 pathkey
.pointer
= b
->path
;
92 return uhash_hashChars(namekey
)+37*uhash_hashChars(pathkey
);
95 /* compares two entries */
96 static UBool U_CALLCONV
97 compareEntries(const UHashTok p1
, const UHashTok p2
) {
98 UStringPrepKey
*b1
= (UStringPrepKey
*)p1
.pointer
;
99 UStringPrepKey
*b2
= (UStringPrepKey
*)p2
.pointer
;
100 UHashTok name1
, name2
, path1
, path2
;
101 name1
.pointer
= b1
->name
;
102 name2
.pointer
= b2
->name
;
103 path1
.pointer
= b1
->path
;
104 path2
.pointer
= b2
->path
;
105 return ((UBool
)(uhash_compareChars(name1
, name2
) &
106 uhash_compareChars(path1
, path2
)));
110 usprep_unload(UStringPrepProfile
* data
){
111 udata_close(data
->sprepData
);
115 usprep_internal_flushCache(UBool noRefCount
){
116 UStringPrepProfile
*profile
= NULL
;
117 UStringPrepKey
*key
= NULL
;
119 int32_t deletedNum
= 0;
120 const UHashElement
*e
;
123 * if shared data hasn't even been lazy evaluated yet
126 umtx_lock(&usprepMutex
);
127 if (SHARED_DATA_HASHTABLE
== NULL
) {
128 umtx_unlock(&usprepMutex
);
132 /*creates an enumeration to iterate through every element in the table */
133 while ((e
= uhash_nextElement(SHARED_DATA_HASHTABLE
, &pos
)) != NULL
)
135 profile
= (UStringPrepProfile
*) e
->value
.pointer
;
136 key
= (UStringPrepKey
*) e
->key
.pointer
;
138 if ((noRefCount
== FALSE
&& profile
->refCount
== 0) ||
141 uhash_removeElement(SHARED_DATA_HASHTABLE
, e
);
143 /* unload the data */
144 usprep_unload(profile
);
146 if(key
->name
!= NULL
) {
147 uprv_free(key
->name
);
150 if(key
->path
!= NULL
) {
151 uprv_free(key
->path
);
159 umtx_unlock(&usprepMutex
);
164 /* Works just like ucnv_flushCache()
167 return usprep_internal_flushCache(FALSE);
171 static UBool U_CALLCONV
usprep_cleanup(void){
172 if (SHARED_DATA_HASHTABLE
!= NULL
) {
173 usprep_internal_flushCache(TRUE
);
174 if (SHARED_DATA_HASHTABLE
!= NULL
&& uhash_count(SHARED_DATA_HASHTABLE
) == 0) {
175 uhash_close(SHARED_DATA_HASHTABLE
);
176 SHARED_DATA_HASHTABLE
= NULL
;
180 umtx_destroy(&usprepMutex
); /* Don't worry about destroying the mutex even */
181 /* if the hash table still exists. The mutex */
182 /* will lazily re-init itself if needed. */
183 return (SHARED_DATA_HASHTABLE
== NULL
);
189 umtx_init(&usprepMutex
);
192 /** Initializes the cache for resources */
194 initCache(UErrorCode
*status
) {
195 UBool makeCache
= FALSE
;
196 umtx_lock(&usprepMutex
);
197 makeCache
= (SHARED_DATA_HASHTABLE
== NULL
);
198 umtx_unlock(&usprepMutex
);
200 UHashtable
*newCache
= uhash_open(hashEntry
, compareEntries
, NULL
, status
);
201 if (U_SUCCESS(*status
)) {
202 umtx_lock(&usprepMutex
);
203 if(SHARED_DATA_HASHTABLE
== NULL
) {
204 SHARED_DATA_HASHTABLE
= newCache
;
205 ucln_common_registerCleanup(UCLN_COMMON_USPREP
, usprep_cleanup
);
208 umtx_unlock(&usprepMutex
);
209 if(newCache
!= NULL
) {
210 uhash_close(newCache
);
216 static UBool U_CALLCONV
217 loadData(UStringPrepProfile
* profile
,
221 UErrorCode
* errorCode
) {
222 /* load Unicode SPREP data from file */
223 UTrie _sprepTrie
={ 0,0,0,0,0,0,0 };
224 UDataMemory
*dataMemory
;
225 const int32_t *p
=NULL
;
227 UVersionInfo normUnicodeVersion
;
228 int32_t normUniVer
, sprepUniVer
, normCorrVer
;
230 if(errorCode
==NULL
|| U_FAILURE(*errorCode
)) {
234 /* open the data outside the mutex block */
235 //TODO: change the path
236 dataMemory
=udata_openChoice(path
, type
, name
, isSPrepAcceptable
, NULL
, errorCode
);
237 if(U_FAILURE(*errorCode
)) {
241 p
=(const int32_t *)udata_getMemory(dataMemory
);
242 pb
=(const uint8_t *)(p
+_SPREP_INDEX_TOP
);
243 utrie_unserialize(&_sprepTrie
, pb
, p
[_SPREP_INDEX_TRIE_SIZE
], errorCode
);
244 _sprepTrie
.getFoldingOffset
=getSPrepFoldingOffset
;
247 if(U_FAILURE(*errorCode
)) {
248 udata_close(dataMemory
);
252 /* in the mutex block, set the data for this process */
253 umtx_lock(&usprepMutex
);
254 if(profile
->sprepData
==NULL
) {
255 profile
->sprepData
=dataMemory
;
257 uprv_memcpy(&profile
->indexes
, p
, sizeof(profile
->indexes
));
258 uprv_memcpy(&profile
->sprepTrie
, &_sprepTrie
, sizeof(UTrie
));
260 p
=(const int32_t *)udata_getMemory(profile
->sprepData
);
262 umtx_unlock(&usprepMutex
);
263 /* initialize some variables */
264 profile
->mappingData
=(uint16_t *)((uint8_t *)(p
+_SPREP_INDEX_TOP
)+profile
->indexes
[_SPREP_INDEX_TRIE_SIZE
]);
266 unorm_getUnicodeVersion(&normUnicodeVersion
, errorCode
);
267 normUniVer
= (normUnicodeVersion
[0] << 24) + (normUnicodeVersion
[1] << 16) +
268 (normUnicodeVersion
[2] << 8 ) + (normUnicodeVersion
[3]);
269 sprepUniVer
= (dataVersion
[0] << 24) + (dataVersion
[1] << 16) +
270 (dataVersion
[2] << 8 ) + (dataVersion
[3]);
271 normCorrVer
= profile
->indexes
[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION
];
273 if(U_FAILURE(*errorCode
)){
274 udata_close(dataMemory
);
277 if( normUniVer
< sprepUniVer
&& /* the Unicode version of SPREP file must be less than the Unicode Vesion of the normalization data */
278 normUniVer
< normCorrVer
&& /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Vesion of the normalization data */
279 ((profile
->indexes
[_SPREP_OPTIONS
] & _SPREP_NORMALIZATION_ON
) > 0) /* normalization turned on*/
281 *errorCode
= U_INVALID_FORMAT_ERROR
;
282 udata_close(dataMemory
);
285 profile
->isDataLoaded
= TRUE
;
287 /* if a different thread set it first, then close the extra data */
288 if(dataMemory
!=NULL
) {
289 udata_close(dataMemory
); /* NULL if it was set correctly */
293 return profile
->isDataLoaded
;
296 static UStringPrepProfile
*
297 usprep_getProfile(const char* path
,
301 UStringPrepProfile
* profile
= NULL
;
305 if(U_FAILURE(*status
)){
309 UStringPrepKey stackKey
;
311 * const is cast way to save malloc, strcpy and free calls
312 * we use the passed in pointers for fetching the data from the
313 * hash table which is safe
315 stackKey
.name
= (char*) name
;
316 stackKey
.path
= (char*) path
;
318 /* fetch the data from the cache */
319 umtx_lock(&usprepMutex
);
320 profile
= (UStringPrepProfile
*) (uhash_get(SHARED_DATA_HASHTABLE
,&stackKey
));
321 umtx_unlock(&usprepMutex
);
324 UStringPrepKey
* key
= (UStringPrepKey
*) uprv_malloc(sizeof(UStringPrepKey
));
326 *status
= U_MEMORY_ALLOCATION_ERROR
;
329 /* else load the data and put the data in the cache */
330 profile
= (UStringPrepProfile
*) uprv_malloc(sizeof(UStringPrepProfile
));
332 *status
= U_MEMORY_ALLOCATION_ERROR
;
337 /* initialize the data struct members */
338 uprv_memset(profile
->indexes
,0,sizeof(profile
->indexes
));
339 profile
->mappingData
= NULL
;
340 profile
->sprepData
= NULL
;
341 profile
->refCount
= 0;
343 /* initialize the key memebers */
344 key
->name
= (char*) uprv_malloc(uprv_strlen(name
)+1);
345 if(key
->name
== NULL
){
346 *status
= U_MEMORY_ALLOCATION_ERROR
;
352 uprv_strcpy(key
->name
, name
);
357 key
->path
= (char*) uprv_malloc(uprv_strlen(path
)+1);
358 if(key
->path
== NULL
){
359 *status
= U_MEMORY_ALLOCATION_ERROR
;
360 uprv_free(key
->name
);
365 uprv_strcpy(key
->path
, path
);
369 if(!loadData(profile
, path
, name
, _SPREP_DATA_TYPE
, status
) || U_FAILURE(*status
) ){
370 uprv_free(key
->path
);
371 uprv_free(key
->name
);
377 /* get the options */
378 profile
->doNFKC
= (UBool
)((profile
->indexes
[_SPREP_OPTIONS
] & _SPREP_NORMALIZATION_ON
) > 0);
379 profile
->checkBiDi
= (UBool
)((profile
->indexes
[_SPREP_OPTIONS
] & _SPREP_CHECK_BIDI_ON
) > 0);
381 if(profile
->checkBiDi
) {
382 profile
->bdp
= ubidi_getSingleton(status
);
383 if(U_FAILURE(*status
)) {
384 usprep_unload(profile
);
385 uprv_free(key
->path
);
386 uprv_free(key
->name
);
395 umtx_lock(&usprepMutex
);
396 /* add the data object to the cache */
397 uhash_put(SHARED_DATA_HASHTABLE
, key
, profile
, status
);
398 umtx_unlock(&usprepMutex
);
400 umtx_lock(&usprepMutex
);
401 /* increment the refcount */
403 umtx_unlock(&usprepMutex
);
408 U_CAPI UStringPrepProfile
* U_EXPORT2
409 usprep_open(const char* path
,
413 if(status
== NULL
|| U_FAILURE(*status
)){
416 /* initialize the mutex */
419 /* initialize the profile struct members */
420 return usprep_getProfile(path
,name
,status
);
423 U_CAPI
void U_EXPORT2
424 usprep_close(UStringPrepProfile
* profile
){
429 umtx_lock(&usprepMutex
);
430 /* decrement the ref count*/
431 if(profile
->refCount
> 0){
434 umtx_unlock(&usprepMutex
);
439 uprv_syntaxError(const UChar
* rules
,
442 UParseError
* parseError
){
443 if(parseError
== NULL
){
446 parseError
->offset
= pos
;
447 parseError
->line
= 0 ; // we are not using line numbers
450 int32_t start
= (pos
<=U_PARSE_CONTEXT_LEN
)? 0 : (pos
- (U_PARSE_CONTEXT_LEN
-1));
453 u_memcpy(parseError
->preContext
,rules
+start
,limit
-start
);
454 //null terminate the buffer
455 parseError
->preContext
[limit
-start
] = 0;
457 // for post-context; include error rules[pos]
459 limit
= start
+ (U_PARSE_CONTEXT_LEN
-1);
460 if (limit
> rulesLen
) {
463 if (start
< rulesLen
) {
464 u_memcpy(parseError
->postContext
,rules
+start
,limit
-start
);
466 //null terminate the buffer
467 parseError
->postContext
[limit
-start
]= 0;
471 static inline UStringPrepType
472 getValues(uint16_t trieWord
, int16_t& value
, UBool
& isIndex
){
474 UStringPrepType type
;
477 * Initial value stored in the mapping table
478 * just return USPREP_TYPE_LIMIT .. so that
479 * the source codepoint is copied to the destination
481 type
= USPREP_TYPE_LIMIT
;
484 }else if(trieWord
>= _SPREP_TYPE_THRESHOLD
){
485 type
= (UStringPrepType
) (trieWord
- _SPREP_TYPE_THRESHOLD
);
491 /* ascertain if the value is index or delta */
494 value
= trieWord
>> 2; //mask off the lower 2 bits and shift
497 value
= (int16_t)trieWord
;
498 value
= (value
>> 2);
501 if((trieWord
>>2) == _SPREP_MAX_INDEX_VALUE
){
502 type
= USPREP_DELETE
;
513 usprep_map( const UStringPrepProfile
* profile
,
514 const UChar
* src
, int32_t srcLength
,
515 UChar
* dest
, int32_t destCapacity
,
517 UParseError
* parseError
,
518 UErrorCode
* status
){
523 UBool allowUnassigned
= (UBool
) ((options
& USPREP_ALLOW_UNASSIGNED
)>0);
524 UStringPrepType type
;
527 const int32_t* indexes
= profile
->indexes
;
529 // no error checking the caller check for error and arguments
530 // no string length check the caller finds out the string length
532 for(srcIndex
=0;srcIndex
<srcLength
;){
535 U16_NEXT(src
,srcIndex
,srcLength
,ch
);
539 UTRIE_GET16(&profile
->sprepTrie
,ch
,result
);
541 type
= getValues(result
, value
, isIndex
);
543 // check if the source codepoint is unassigned
544 if(type
== USPREP_UNASSIGNED
&& allowUnassigned
== FALSE
){
546 uprv_syntaxError(src
,srcIndex
-U16_LENGTH(ch
), srcLength
,parseError
);
547 *status
= U_STRINGPREP_UNASSIGNED_ERROR
;
550 }else if(type
== USPREP_MAP
){
552 int32_t index
, length
;
556 if(index
>= indexes
[_SPREP_ONE_UCHAR_MAPPING_INDEX_START
] &&
557 index
< indexes
[_SPREP_TWO_UCHARS_MAPPING_INDEX_START
]){
559 }else if(index
>= indexes
[_SPREP_TWO_UCHARS_MAPPING_INDEX_START
] &&
560 index
< indexes
[_SPREP_THREE_UCHARS_MAPPING_INDEX_START
]){
562 }else if(index
>= indexes
[_SPREP_THREE_UCHARS_MAPPING_INDEX_START
] &&
563 index
< indexes
[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START
]){
566 length
= profile
->mappingData
[index
++];
570 /* copy mapping to destination */
571 for(int32_t i
=0; i
< length
; i
++){
572 if(destIndex
< destCapacity
){
573 dest
[destIndex
] = profile
->mappingData
[index
+i
];
575 destIndex
++; /* for pre-flighting */
579 // subtract the delta to arrive at the code point
583 }else if(type
==USPREP_DELETE
){
584 // just consume the codepoint and contine
587 //copy the code point into destination
589 if(destIndex
< destCapacity
){
590 dest
[destIndex
] = (UChar
)ch
;
594 if(destIndex
+1 < destCapacity
){
595 dest
[destIndex
] = U16_LEAD(ch
);
596 dest
[destIndex
+1] = U16_TRAIL(ch
);
603 return u_terminateUChars(dest
, destCapacity
, destIndex
, status
);
608 usprep_normalize( const UChar
* src
, int32_t srcLength
,
609 UChar
* dest
, int32_t destCapacity
,
610 UErrorCode
* status
){
612 * Option UNORM_BEFORE_PRI_29:
614 * IDNA as interpreted by IETF members (see unicode mailing list 2004H1)
615 * requires strict adherence to Unicode 3.2 normalization,
616 * including buggy composition from before fixing Public Review Issue #29.
617 * Note that this results in some valid but nonsensical text to be
618 * either corrupted or rejected, depending on the text.
619 * See http://www.unicode.org/review/resolved-pri.html#pri29
620 * See unorm.cpp and cnormtst.c
622 return unorm_normalize(
624 UNORM_NFKC
, UNORM_UNICODE_3_2
|UNORM_BEFORE_PRI_29
,
631 1) Map -- For each character in the input, check if it has a mapping
632 and, if so, replace it with its mapping.
634 2) Normalize -- Possibly normalize the result of step 1 using Unicode
637 3) Prohibit -- Check for any characters that are not allowed in the
638 output. If any are found, return an error.
640 4) Check bidi -- Possibly check for right-to-left characters, and if
641 any are found, make sure that the whole string satisfies the
642 requirements for bidirectional strings. If the string does not
643 satisfy the requirements for bidirectional strings, return an
645 [Unicode3.2] defines several bidirectional categories; each character
646 has one bidirectional category assigned to it. For the purposes of
647 the requirements below, an "RandALCat character" is a character that
648 has Unicode bidirectional categories "R" or "AL"; an "LCat character"
649 is a character that has Unicode bidirectional category "L". Note
652 that there are many characters which fall in neither of the above
653 definitions; Latin digits (<U+0030> through <U+0039>) are examples of
654 this because they have bidirectional category "EN".
656 In any profile that specifies bidirectional character handling, all
657 three of the following requirements MUST be met:
659 1) The characters in section 5.8 MUST be prohibited.
661 2) If a string contains any RandALCat character, the string MUST NOT
662 contain any LCat character.
664 3) If a string contains any RandALCat character, a RandALCat
665 character MUST be the first character of the string, and a
666 RandALCat character MUST be the last character of the string.
669 #define MAX_STACK_BUFFER_SIZE 300
672 U_CAPI
int32_t U_EXPORT2
673 usprep_prepare( const UStringPrepProfile
* profile
,
674 const UChar
* src
, int32_t srcLength
,
675 UChar
* dest
, int32_t destCapacity
,
677 UParseError
* parseError
,
678 UErrorCode
* status
){
680 // check error status
681 if(status
== NULL
|| U_FAILURE(*status
)){
686 if(profile
==NULL
|| src
==NULL
|| srcLength
<-1 || (dest
==NULL
&& destCapacity
!=0)) {
687 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
691 UChar b1Stack
[MAX_STACK_BUFFER_SIZE
], b2Stack
[MAX_STACK_BUFFER_SIZE
];
692 UChar
*b1
= b1Stack
, *b2
= b2Stack
;
693 int32_t b1Len
, b2Len
=0,
694 b1Capacity
= MAX_STACK_BUFFER_SIZE
,
695 b2Capacity
= MAX_STACK_BUFFER_SIZE
;
698 UCharDirection direction
=U_CHAR_DIRECTION_COUNT
, firstCharDir
=U_CHAR_DIRECTION_COUNT
;
699 UBool leftToRight
=FALSE
, rightToLeft
=FALSE
;
700 int32_t rtlPos
=-1, ltrPos
=-1;
702 //get the string length
704 srcLength
= u_strlen(src
);
707 b1Len
= usprep_map(profile
, src
, srcLength
, b1
, b1Capacity
, options
, parseError
, status
);
709 if(*status
== U_BUFFER_OVERFLOW_ERROR
){
710 // redo processing of string
711 /* we do not have enough room so grow the buffer*/
712 b1
= (UChar
*) uprv_malloc(b1Len
* U_SIZEOF_UCHAR
);
714 *status
= U_MEMORY_ALLOCATION_ERROR
;
718 *status
= U_ZERO_ERROR
; // reset error
720 b1Len
= usprep_map(profile
, src
, srcLength
, b1
, b1Len
, options
, parseError
, status
);
725 if(profile
->doNFKC
== TRUE
){
726 b2Len
= usprep_normalize(b1
,b1Len
, b2
,b2Capacity
,status
);
728 if(*status
== U_BUFFER_OVERFLOW_ERROR
){
729 // redo processing of string
730 /* we do not have enough room so grow the buffer*/
731 b2
= (UChar
*) uprv_malloc(b2Len
* U_SIZEOF_UCHAR
);
733 *status
= U_MEMORY_ALLOCATION_ERROR
;
737 *status
= U_ZERO_ERROR
; // reset error
739 b2Len
= usprep_normalize(b1
,b1Len
, b2
,b2Len
,status
);
749 if(U_FAILURE(*status
)){
754 UStringPrepType type
;
758 // Prohibit and checkBiDi in one pass
759 for(b2Index
=0; b2Index
<b2Len
;){
763 U16_NEXT(b2
, b2Index
, b2Len
, ch
);
765 UTRIE_GET16(&profile
->sprepTrie
,ch
,result
);
767 type
= getValues(result
, value
, isIndex
);
769 if( type
== USPREP_PROHIBITED
||
770 ((result
< _SPREP_TYPE_THRESHOLD
) && (result
& 0x01) /* first bit says it the code point is prohibited*/)
772 *status
= U_STRINGPREP_PROHIBITED_ERROR
;
773 uprv_syntaxError(b1
, b2Index
-U16_LENGTH(ch
), b2Len
, parseError
);
777 if(profile
->checkBiDi
) {
778 direction
= ubidi_getClass(profile
->bdp
, ch
);
779 if(firstCharDir
== U_CHAR_DIRECTION_COUNT
){
780 firstCharDir
= direction
;
782 if(direction
== U_LEFT_TO_RIGHT
){
786 if(direction
== U_RIGHT_TO_LEFT
|| direction
== U_RIGHT_TO_LEFT_ARABIC
){
792 if(profile
->checkBiDi
== TRUE
){
794 if( leftToRight
== TRUE
&& rightToLeft
== TRUE
){
795 *status
= U_STRINGPREP_CHECK_BIDI_ERROR
;
796 uprv_syntaxError(b2
,(rtlPos
>ltrPos
) ? rtlPos
: ltrPos
, b2Len
, parseError
);
801 if( rightToLeft
== TRUE
&&
802 !((firstCharDir
== U_RIGHT_TO_LEFT
|| firstCharDir
== U_RIGHT_TO_LEFT_ARABIC
) &&
803 (direction
== U_RIGHT_TO_LEFT
|| direction
== U_RIGHT_TO_LEFT_ARABIC
))
805 *status
= U_STRINGPREP_CHECK_BIDI_ERROR
;
806 uprv_syntaxError(b2
, rtlPos
, b2Len
, parseError
);
810 if(b2Len
>0 && b2Len
<= destCapacity
){
811 uprv_memmove(dest
,b2
, b2Len
*U_SIZEOF_UCHAR
);
820 if(b2
!=b1Stack
&& b2
!=b2Stack
&& b2
!=b1
/* b1 should not be freed twice */){
824 return u_terminateUChars(dest
, destCapacity
, b2Len
, status
);
828 /* data swapping ------------------------------------------------------------ */
830 U_CAPI
int32_t U_EXPORT2
831 usprep_swap(const UDataSwapper
*ds
,
832 const void *inData
, int32_t length
, void *outData
,
833 UErrorCode
*pErrorCode
) {
834 const UDataInfo
*pInfo
;
837 const uint8_t *inBytes
;
840 const int32_t *inIndexes
;
843 int32_t i
, offset
, count
, size
;
845 /* udata_swapDataHeader checks the arguments */
846 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
847 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
851 /* check data format and format version */
852 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
854 pInfo
->dataFormat
[0]==0x53 && /* dataFormat="SPRP" */
855 pInfo
->dataFormat
[1]==0x50 &&
856 pInfo
->dataFormat
[2]==0x52 &&
857 pInfo
->dataFormat
[3]==0x50 &&
858 pInfo
->formatVersion
[0]==3
860 udata_printError(ds
, "usprep_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as StringPrep .spp data\n",
861 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
862 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
863 pInfo
->formatVersion
[0]);
864 *pErrorCode
=U_UNSUPPORTED_ERROR
;
868 inBytes
=(const uint8_t *)inData
+headerSize
;
869 outBytes
=(uint8_t *)outData
+headerSize
;
871 inIndexes
=(const int32_t *)inBytes
;
876 udata_printError(ds
, "usprep_swap(): too few bytes (%d after header) for StringPrep .spp data\n",
878 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
883 /* read the first 16 indexes (ICU 2.8/format version 3: _SPREP_INDEX_TOP==16, might grow) */
884 for(i
=0; i
<16; ++i
) {
885 indexes
[i
]=udata_readInt32(ds
, inIndexes
[i
]);
888 /* calculate the total length of the data */
890 16*4+ /* size of indexes[] */
891 indexes
[_SPREP_INDEX_TRIE_SIZE
]+
892 indexes
[_SPREP_INDEX_MAPPING_DATA_SIZE
];
896 udata_printError(ds
, "usprep_swap(): too few bytes (%d after header) for all of StringPrep .spp data\n",
898 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
902 /* copy the data for inaccessible bytes */
903 if(inBytes
!=outBytes
) {
904 uprv_memcpy(outBytes
, inBytes
, size
);
909 /* swap the int32_t indexes[] */
911 ds
->swapArray32(ds
, inBytes
, count
, outBytes
, pErrorCode
);
915 count
=indexes
[_SPREP_INDEX_TRIE_SIZE
];
916 utrie_swap(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
919 /* swap the uint16_t mappingTable[] */
920 count
=indexes
[_SPREP_INDEX_MAPPING_DATA_SIZE
];
921 ds
->swapArray16(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
925 return headerSize
+size
;
928 #endif /* #if !UCONFIG_NO_IDNA */