2 *******************************************************************************
4 * Copyright (C) 2003-2012, 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"
35 #include "ubidi_props.h"
42 Static cache for already opened StringPrep profiles
44 static UHashtable
*SHARED_DATA_HASHTABLE
= NULL
;
46 static UMutex usprepMutex
= U_MUTEX_INITIALIZER
;
48 /* format version of spp file */
49 //static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
51 /* the Unicode version of the sprep data */
52 static UVersionInfo dataVersion
={ 0, 0, 0, 0 };
54 /* Profile names must be aligned to UStringPrepProfileType */
55 static const char * const PROFILE_NAMES
[] = {
56 "rfc3491", /* USPREP_RFC3491_NAMEPREP */
57 "rfc3530cs", /* USPREP_RFC3530_NFS4_CS_PREP */
58 "rfc3530csci", /* USPREP_RFC3530_NFS4_CS_PREP_CI */
59 "rfc3491", /* USPREP_RFC3530_NSF4_CIS_PREP */
60 "rfc3530mixp", /* USPREP_RFC3530_NSF4_MIXED_PREP_PREFIX */
61 "rfc3491", /* USPREP_RFC3530_NSF4_MIXED_PREP_SUFFIX */
62 "rfc3722", /* USPREP_RFC3722_ISCSI */
63 "rfc3920node", /* USPREP_RFC3920_NODEPREP */
64 "rfc3920res", /* USPREP_RFC3920_RESOURCEPREP */
65 "rfc4011", /* USPREP_RFC4011_MIB */
66 "rfc4013", /* USPREP_RFC4013_SASLPREP */
67 "rfc4505", /* USPREP_RFC4505_TRACE */
68 "rfc4518", /* USPREP_RFC4518_LDAP */
69 "rfc4518ci", /* USPREP_RFC4518_LDAP_CI */
72 static UBool U_CALLCONV
73 isSPrepAcceptable(void * /* context */,
74 const char * /* type */,
75 const char * /* name */,
76 const UDataInfo
*pInfo
) {
79 pInfo
->isBigEndian
==U_IS_BIG_ENDIAN
&&
80 pInfo
->charsetFamily
==U_CHARSET_FAMILY
&&
81 pInfo
->dataFormat
[0]==0x53 && /* dataFormat="SPRP" */
82 pInfo
->dataFormat
[1]==0x50 &&
83 pInfo
->dataFormat
[2]==0x52 &&
84 pInfo
->dataFormat
[3]==0x50 &&
85 pInfo
->formatVersion
[0]==3 &&
86 pInfo
->formatVersion
[2]==UTRIE_SHIFT
&&
87 pInfo
->formatVersion
[3]==UTRIE_INDEX_SHIFT
89 //uprv_memcpy(formatVersion, pInfo->formatVersion, 4);
90 uprv_memcpy(dataVersion
, pInfo
->dataVersion
, 4);
97 static int32_t U_CALLCONV
98 getSPrepFoldingOffset(uint32_t data
) {
100 return (int32_t)data
;
104 /* hashes an entry */
105 static int32_t U_CALLCONV
106 hashEntry(const UHashTok parm
) {
107 UStringPrepKey
*b
= (UStringPrepKey
*)parm
.pointer
;
108 UHashTok namekey
, pathkey
;
109 namekey
.pointer
= b
->name
;
110 pathkey
.pointer
= b
->path
;
111 return uhash_hashChars(namekey
)+37*uhash_hashChars(pathkey
);
114 /* compares two entries */
115 static UBool U_CALLCONV
116 compareEntries(const UHashTok p1
, const UHashTok p2
) {
117 UStringPrepKey
*b1
= (UStringPrepKey
*)p1
.pointer
;
118 UStringPrepKey
*b2
= (UStringPrepKey
*)p2
.pointer
;
119 UHashTok name1
, name2
, path1
, path2
;
120 name1
.pointer
= b1
->name
;
121 name2
.pointer
= b2
->name
;
122 path1
.pointer
= b1
->path
;
123 path2
.pointer
= b2
->path
;
124 return ((UBool
)(uhash_compareChars(name1
, name2
) &
125 uhash_compareChars(path1
, path2
)));
129 usprep_unload(UStringPrepProfile
* data
){
130 udata_close(data
->sprepData
);
134 usprep_internal_flushCache(UBool noRefCount
){
135 UStringPrepProfile
*profile
= NULL
;
136 UStringPrepKey
*key
= NULL
;
138 int32_t deletedNum
= 0;
139 const UHashElement
*e
;
142 * if shared data hasn't even been lazy evaluated yet
145 umtx_lock(&usprepMutex
);
146 if (SHARED_DATA_HASHTABLE
== NULL
) {
147 umtx_unlock(&usprepMutex
);
151 /*creates an enumeration to iterate through every element in the table */
152 while ((e
= uhash_nextElement(SHARED_DATA_HASHTABLE
, &pos
)) != NULL
)
154 profile
= (UStringPrepProfile
*) e
->value
.pointer
;
155 key
= (UStringPrepKey
*) e
->key
.pointer
;
157 if ((noRefCount
== FALSE
&& profile
->refCount
== 0) ||
160 uhash_removeElement(SHARED_DATA_HASHTABLE
, e
);
162 /* unload the data */
163 usprep_unload(profile
);
165 if(key
->name
!= NULL
) {
166 uprv_free(key
->name
);
169 if(key
->path
!= NULL
) {
170 uprv_free(key
->path
);
178 umtx_unlock(&usprepMutex
);
183 /* Works just like ucnv_flushCache()
186 return usprep_internal_flushCache(FALSE);
190 static UBool U_CALLCONV
usprep_cleanup(void){
191 if (SHARED_DATA_HASHTABLE
!= NULL
) {
192 usprep_internal_flushCache(TRUE
);
193 if (SHARED_DATA_HASHTABLE
!= NULL
&& uhash_count(SHARED_DATA_HASHTABLE
) == 0) {
194 uhash_close(SHARED_DATA_HASHTABLE
);
195 SHARED_DATA_HASHTABLE
= NULL
;
199 return (SHARED_DATA_HASHTABLE
== NULL
);
204 /** Initializes the cache for resources */
206 initCache(UErrorCode
*status
) {
208 UMTX_CHECK(&usprepMutex
, (SHARED_DATA_HASHTABLE
== NULL
), makeCache
);
210 UHashtable
*newCache
= uhash_open(hashEntry
, compareEntries
, NULL
, status
);
211 if (U_SUCCESS(*status
)) {
212 umtx_lock(&usprepMutex
);
213 if(SHARED_DATA_HASHTABLE
== NULL
) {
214 SHARED_DATA_HASHTABLE
= newCache
;
215 ucln_common_registerCleanup(UCLN_COMMON_USPREP
, usprep_cleanup
);
218 umtx_unlock(&usprepMutex
);
220 if(newCache
!= NULL
) {
221 uhash_close(newCache
);
226 static UBool U_CALLCONV
227 loadData(UStringPrepProfile
* profile
,
231 UErrorCode
* errorCode
) {
232 /* load Unicode SPREP data from file */
233 UTrie _sprepTrie
={ 0,0,0,0,0,0,0 };
234 UDataMemory
*dataMemory
;
235 const int32_t *p
=NULL
;
237 UVersionInfo normUnicodeVersion
;
238 int32_t normUniVer
, sprepUniVer
, normCorrVer
;
240 if(errorCode
==NULL
|| U_FAILURE(*errorCode
)) {
244 /* open the data outside the mutex block */
245 //TODO: change the path
246 dataMemory
=udata_openChoice(path
, type
, name
, isSPrepAcceptable
, NULL
, errorCode
);
247 if(U_FAILURE(*errorCode
)) {
251 p
=(const int32_t *)udata_getMemory(dataMemory
);
252 pb
=(const uint8_t *)(p
+_SPREP_INDEX_TOP
);
253 utrie_unserialize(&_sprepTrie
, pb
, p
[_SPREP_INDEX_TRIE_SIZE
], errorCode
);
254 _sprepTrie
.getFoldingOffset
=getSPrepFoldingOffset
;
257 if(U_FAILURE(*errorCode
)) {
258 udata_close(dataMemory
);
262 /* in the mutex block, set the data for this process */
263 umtx_lock(&usprepMutex
);
264 if(profile
->sprepData
==NULL
) {
265 profile
->sprepData
=dataMemory
;
267 uprv_memcpy(&profile
->indexes
, p
, sizeof(profile
->indexes
));
268 uprv_memcpy(&profile
->sprepTrie
, &_sprepTrie
, sizeof(UTrie
));
270 p
=(const int32_t *)udata_getMemory(profile
->sprepData
);
272 umtx_unlock(&usprepMutex
);
273 /* initialize some variables */
274 profile
->mappingData
=(uint16_t *)((uint8_t *)(p
+_SPREP_INDEX_TOP
)+profile
->indexes
[_SPREP_INDEX_TRIE_SIZE
]);
276 u_getUnicodeVersion(normUnicodeVersion
);
277 normUniVer
= (normUnicodeVersion
[0] << 24) + (normUnicodeVersion
[1] << 16) +
278 (normUnicodeVersion
[2] << 8 ) + (normUnicodeVersion
[3]);
279 sprepUniVer
= (dataVersion
[0] << 24) + (dataVersion
[1] << 16) +
280 (dataVersion
[2] << 8 ) + (dataVersion
[3]);
281 normCorrVer
= profile
->indexes
[_SPREP_NORM_CORRECTNS_LAST_UNI_VERSION
];
283 if(U_FAILURE(*errorCode
)){
284 udata_close(dataMemory
);
287 if( normUniVer
< sprepUniVer
&& /* the Unicode version of SPREP file must be less than the Unicode Vesion of the normalization data */
288 normUniVer
< normCorrVer
&& /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Vesion of the normalization data */
289 ((profile
->indexes
[_SPREP_OPTIONS
] & _SPREP_NORMALIZATION_ON
) > 0) /* normalization turned on*/
291 *errorCode
= U_INVALID_FORMAT_ERROR
;
292 udata_close(dataMemory
);
295 profile
->isDataLoaded
= TRUE
;
297 /* if a different thread set it first, then close the extra data */
298 if(dataMemory
!=NULL
) {
299 udata_close(dataMemory
); /* NULL if it was set correctly */
303 return profile
->isDataLoaded
;
306 static UStringPrepProfile
*
307 usprep_getProfile(const char* path
,
311 UStringPrepProfile
* profile
= NULL
;
315 if(U_FAILURE(*status
)){
319 UStringPrepKey stackKey
;
321 * const is cast way to save malloc, strcpy and free calls
322 * we use the passed in pointers for fetching the data from the
323 * hash table which is safe
325 stackKey
.name
= (char*) name
;
326 stackKey
.path
= (char*) path
;
328 /* fetch the data from the cache */
329 umtx_lock(&usprepMutex
);
330 profile
= (UStringPrepProfile
*) (uhash_get(SHARED_DATA_HASHTABLE
,&stackKey
));
331 if(profile
!= NULL
) {
334 umtx_unlock(&usprepMutex
);
336 if(profile
== NULL
) {
337 /* else load the data and put the data in the cache */
338 LocalMemory
<UStringPrepProfile
> newProfile
;
339 if(newProfile
.allocateInsteadAndReset() == NULL
) {
340 *status
= U_MEMORY_ALLOCATION_ERROR
;
345 if(!loadData(newProfile
.getAlias(), path
, name
, _SPREP_DATA_TYPE
, status
) || U_FAILURE(*status
) ){
349 /* get the options */
350 newProfile
->doNFKC
= (UBool
)((newProfile
->indexes
[_SPREP_OPTIONS
] & _SPREP_NORMALIZATION_ON
) > 0);
351 newProfile
->checkBiDi
= (UBool
)((newProfile
->indexes
[_SPREP_OPTIONS
] & _SPREP_CHECK_BIDI_ON
) > 0);
353 if(newProfile
->checkBiDi
) {
354 newProfile
->bdp
= ubidi_getSingleton();
357 LocalMemory
<UStringPrepKey
> key
;
358 LocalMemory
<char> keyName
;
359 LocalMemory
<char> keyPath
;
360 if( key
.allocateInsteadAndReset() == NULL
||
361 keyName
.allocateInsteadAndCopy(uprv_strlen(name
)+1) == NULL
||
363 keyPath
.allocateInsteadAndCopy(uprv_strlen(path
)+1) == NULL
)
365 *status
= U_MEMORY_ALLOCATION_ERROR
;
366 usprep_unload(newProfile
.getAlias());
370 umtx_lock(&usprepMutex
);
371 // If another thread already inserted the same key/value, refcount and cleanup our thread data
372 profile
= (UStringPrepProfile
*) (uhash_get(SHARED_DATA_HASHTABLE
,&stackKey
));
373 if(profile
!= NULL
) {
375 usprep_unload(newProfile
.getAlias());
378 /* initialize the key members */
379 key
->name
= keyName
.orphan();
380 uprv_strcpy(key
->name
, name
);
382 key
->path
= keyPath
.orphan();
383 uprv_strcpy(key
->path
, path
);
385 profile
= newProfile
.orphan();
387 /* add the data object to the cache */
388 profile
->refCount
= 1;
389 uhash_put(SHARED_DATA_HASHTABLE
, key
.orphan(), profile
, status
);
391 umtx_unlock(&usprepMutex
);
397 U_CAPI UStringPrepProfile
* U_EXPORT2
398 usprep_open(const char* path
,
402 if(status
== NULL
|| U_FAILURE(*status
)){
406 /* initialize the profile struct members */
407 return usprep_getProfile(path
,name
,status
);
410 U_CAPI UStringPrepProfile
* U_EXPORT2
411 usprep_openByType(UStringPrepProfileType type
,
412 UErrorCode
* status
) {
413 if(status
== NULL
|| U_FAILURE(*status
)){
416 int32_t index
= (int32_t)type
;
417 if (index
< 0 || index
>= (int32_t)(sizeof(PROFILE_NAMES
)/sizeof(PROFILE_NAMES
[0]))) {
418 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
421 return usprep_open(NULL
, PROFILE_NAMES
[index
], status
);
424 U_CAPI
void U_EXPORT2
425 usprep_close(UStringPrepProfile
* profile
){
430 umtx_lock(&usprepMutex
);
431 /* decrement the ref count*/
432 if(profile
->refCount
> 0){
435 umtx_unlock(&usprepMutex
);
440 uprv_syntaxError(const UChar
* rules
,
443 UParseError
* parseError
){
444 if(parseError
== NULL
){
447 parseError
->offset
= pos
;
448 parseError
->line
= 0 ; // we are not using line numbers
451 int32_t start
= (pos
< U_PARSE_CONTEXT_LEN
)? 0 : (pos
- (U_PARSE_CONTEXT_LEN
-1));
454 u_memcpy(parseError
->preContext
,rules
+start
,limit
-start
);
455 //null terminate the buffer
456 parseError
->preContext
[limit
-start
] = 0;
458 // for post-context; include error rules[pos]
460 limit
= start
+ (U_PARSE_CONTEXT_LEN
-1);
461 if (limit
> rulesLen
) {
464 if (start
< rulesLen
) {
465 u_memcpy(parseError
->postContext
,rules
+start
,limit
-start
);
467 //null terminate the buffer
468 parseError
->postContext
[limit
-start
]= 0;
472 static inline UStringPrepType
473 getValues(uint16_t trieWord
, int16_t& value
, UBool
& isIndex
){
475 UStringPrepType type
;
478 * Initial value stored in the mapping table
479 * just return USPREP_TYPE_LIMIT .. so that
480 * the source codepoint is copied to the destination
482 type
= USPREP_TYPE_LIMIT
;
485 }else if(trieWord
>= _SPREP_TYPE_THRESHOLD
){
486 type
= (UStringPrepType
) (trieWord
- _SPREP_TYPE_THRESHOLD
);
492 /* ascertain if the value is index or delta */
495 value
= trieWord
>> 2; //mask off the lower 2 bits and shift
498 value
= (int16_t)trieWord
;
499 value
= (value
>> 2);
502 if((trieWord
>>2) == _SPREP_MAX_INDEX_VALUE
){
503 type
= USPREP_DELETE
;
514 usprep_map( const UStringPrepProfile
* profile
,
515 const UChar
* src
, int32_t srcLength
,
516 UChar
* dest
, int32_t destCapacity
,
518 UParseError
* parseError
,
519 UErrorCode
* status
){
524 UBool allowUnassigned
= (UBool
) ((options
& USPREP_ALLOW_UNASSIGNED
)>0);
525 UStringPrepType type
;
528 const int32_t* indexes
= profile
->indexes
;
530 // no error checking the caller check for error and arguments
531 // no string length check the caller finds out the string length
533 for(srcIndex
=0;srcIndex
<srcLength
;){
536 U16_NEXT(src
,srcIndex
,srcLength
,ch
);
540 UTRIE_GET16(&profile
->sprepTrie
,ch
,result
);
542 type
= getValues(result
, value
, isIndex
);
544 // check if the source codepoint is unassigned
545 if(type
== USPREP_UNASSIGNED
&& allowUnassigned
== FALSE
){
547 uprv_syntaxError(src
,srcIndex
-U16_LENGTH(ch
), srcLength
,parseError
);
548 *status
= U_STRINGPREP_UNASSIGNED_ERROR
;
551 }else if(type
== USPREP_MAP
){
553 int32_t index
, length
;
557 if(index
>= indexes
[_SPREP_ONE_UCHAR_MAPPING_INDEX_START
] &&
558 index
< indexes
[_SPREP_TWO_UCHARS_MAPPING_INDEX_START
]){
560 }else if(index
>= indexes
[_SPREP_TWO_UCHARS_MAPPING_INDEX_START
] &&
561 index
< indexes
[_SPREP_THREE_UCHARS_MAPPING_INDEX_START
]){
563 }else if(index
>= indexes
[_SPREP_THREE_UCHARS_MAPPING_INDEX_START
] &&
564 index
< indexes
[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START
]){
567 length
= profile
->mappingData
[index
++];
571 /* copy mapping to destination */
572 for(int32_t i
=0; i
< length
; i
++){
573 if(destIndex
< destCapacity
){
574 dest
[destIndex
] = profile
->mappingData
[index
+i
];
576 destIndex
++; /* for pre-flighting */
580 // subtract the delta to arrive at the code point
584 }else if(type
==USPREP_DELETE
){
585 // just consume the codepoint and contine
588 //copy the code point into destination
590 if(destIndex
< destCapacity
){
591 dest
[destIndex
] = (UChar
)ch
;
595 if(destIndex
+1 < destCapacity
){
596 dest
[destIndex
] = U16_LEAD(ch
);
597 dest
[destIndex
+1] = U16_TRAIL(ch
);
604 return u_terminateUChars(dest
, destCapacity
, destIndex
, status
);
609 usprep_normalize( const UChar
* src
, int32_t srcLength
,
610 UChar
* dest
, int32_t destCapacity
,
611 UErrorCode
* status
){
612 return unorm_normalize(
614 UNORM_NFKC
, UNORM_UNICODE_3_2
,
621 1) Map -- For each character in the input, check if it has a mapping
622 and, if so, replace it with its mapping.
624 2) Normalize -- Possibly normalize the result of step 1 using Unicode
627 3) Prohibit -- Check for any characters that are not allowed in the
628 output. If any are found, return an error.
630 4) Check bidi -- Possibly check for right-to-left characters, and if
631 any are found, make sure that the whole string satisfies the
632 requirements for bidirectional strings. If the string does not
633 satisfy the requirements for bidirectional strings, return an
635 [Unicode3.2] defines several bidirectional categories; each character
636 has one bidirectional category assigned to it. For the purposes of
637 the requirements below, an "RandALCat character" is a character that
638 has Unicode bidirectional categories "R" or "AL"; an "LCat character"
639 is a character that has Unicode bidirectional category "L". Note
642 that there are many characters which fall in neither of the above
643 definitions; Latin digits (<U+0030> through <U+0039>) are examples of
644 this because they have bidirectional category "EN".
646 In any profile that specifies bidirectional character handling, all
647 three of the following requirements MUST be met:
649 1) The characters in section 5.8 MUST be prohibited.
651 2) If a string contains any RandALCat character, the string MUST NOT
652 contain any LCat character.
654 3) If a string contains any RandALCat character, a RandALCat
655 character MUST be the first character of the string, and a
656 RandALCat character MUST be the last character of the string.
659 #define MAX_STACK_BUFFER_SIZE 300
662 U_CAPI
int32_t U_EXPORT2
663 usprep_prepare( const UStringPrepProfile
* profile
,
664 const UChar
* src
, int32_t srcLength
,
665 UChar
* dest
, int32_t destCapacity
,
667 UParseError
* parseError
,
668 UErrorCode
* status
){
670 // check error status
671 if(status
== NULL
|| U_FAILURE(*status
)){
676 if(profile
==NULL
|| src
==NULL
|| srcLength
<-1 || (dest
==NULL
&& destCapacity
!=0)) {
677 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
681 UChar b1Stack
[MAX_STACK_BUFFER_SIZE
], b2Stack
[MAX_STACK_BUFFER_SIZE
];
682 UChar
*b1
= b1Stack
, *b2
= b2Stack
;
683 int32_t b1Len
, b2Len
=0,
684 b1Capacity
= MAX_STACK_BUFFER_SIZE
,
685 b2Capacity
= MAX_STACK_BUFFER_SIZE
;
688 UCharDirection direction
=U_CHAR_DIRECTION_COUNT
, firstCharDir
=U_CHAR_DIRECTION_COUNT
;
689 UBool leftToRight
=FALSE
, rightToLeft
=FALSE
;
690 int32_t rtlPos
=-1, ltrPos
=-1;
692 //get the string length
694 srcLength
= u_strlen(src
);
697 b1Len
= usprep_map(profile
, src
, srcLength
, b1
, b1Capacity
, options
, parseError
, status
);
699 if(*status
== U_BUFFER_OVERFLOW_ERROR
){
700 // redo processing of string
701 /* we do not have enough room so grow the buffer*/
702 b1
= (UChar
*) uprv_malloc(b1Len
* U_SIZEOF_UCHAR
);
704 *status
= U_MEMORY_ALLOCATION_ERROR
;
708 *status
= U_ZERO_ERROR
; // reset error
710 b1Len
= usprep_map(profile
, src
, srcLength
, b1
, b1Len
, options
, parseError
, status
);
715 if(profile
->doNFKC
== TRUE
){
716 b2Len
= usprep_normalize(b1
,b1Len
, b2
,b2Capacity
,status
);
718 if(*status
== U_BUFFER_OVERFLOW_ERROR
){
719 // redo processing of string
720 /* we do not have enough room so grow the buffer*/
721 b2
= (UChar
*) uprv_malloc(b2Len
* U_SIZEOF_UCHAR
);
723 *status
= U_MEMORY_ALLOCATION_ERROR
;
727 *status
= U_ZERO_ERROR
; // reset error
729 b2Len
= usprep_normalize(b1
,b1Len
, b2
,b2Len
,status
);
739 if(U_FAILURE(*status
)){
744 UStringPrepType type
;
748 // Prohibit and checkBiDi in one pass
749 for(b2Index
=0; b2Index
<b2Len
;){
753 U16_NEXT(b2
, b2Index
, b2Len
, ch
);
755 UTRIE_GET16(&profile
->sprepTrie
,ch
,result
);
757 type
= getValues(result
, value
, isIndex
);
759 if( type
== USPREP_PROHIBITED
||
760 ((result
< _SPREP_TYPE_THRESHOLD
) && (result
& 0x01) /* first bit says it the code point is prohibited*/)
762 *status
= U_STRINGPREP_PROHIBITED_ERROR
;
763 uprv_syntaxError(b1
, b2Index
-U16_LENGTH(ch
), b2Len
, parseError
);
767 if(profile
->checkBiDi
) {
768 direction
= ubidi_getClass(profile
->bdp
, ch
);
769 if(firstCharDir
== U_CHAR_DIRECTION_COUNT
){
770 firstCharDir
= direction
;
772 if(direction
== U_LEFT_TO_RIGHT
){
776 if(direction
== U_RIGHT_TO_LEFT
|| direction
== U_RIGHT_TO_LEFT_ARABIC
){
782 if(profile
->checkBiDi
== TRUE
){
784 if( leftToRight
== TRUE
&& rightToLeft
== TRUE
){
785 *status
= U_STRINGPREP_CHECK_BIDI_ERROR
;
786 uprv_syntaxError(b2
,(rtlPos
>ltrPos
) ? rtlPos
: ltrPos
, b2Len
, parseError
);
791 if( rightToLeft
== TRUE
&&
792 !((firstCharDir
== U_RIGHT_TO_LEFT
|| firstCharDir
== U_RIGHT_TO_LEFT_ARABIC
) &&
793 (direction
== U_RIGHT_TO_LEFT
|| direction
== U_RIGHT_TO_LEFT_ARABIC
))
795 *status
= U_STRINGPREP_CHECK_BIDI_ERROR
;
796 uprv_syntaxError(b2
, rtlPos
, b2Len
, parseError
);
800 if(b2Len
>0 && b2Len
<= destCapacity
){
801 uprv_memmove(dest
,b2
, b2Len
*U_SIZEOF_UCHAR
);
810 if(b2
!=b1Stack
&& b2
!=b2Stack
&& b2
!=b1
/* b1 should not be freed twice */){
814 return u_terminateUChars(dest
, destCapacity
, b2Len
, status
);
818 /* data swapping ------------------------------------------------------------ */
820 U_CAPI
int32_t U_EXPORT2
821 usprep_swap(const UDataSwapper
*ds
,
822 const void *inData
, int32_t length
, void *outData
,
823 UErrorCode
*pErrorCode
) {
824 const UDataInfo
*pInfo
;
827 const uint8_t *inBytes
;
830 const int32_t *inIndexes
;
833 int32_t i
, offset
, count
, size
;
835 /* udata_swapDataHeader checks the arguments */
836 headerSize
=udata_swapDataHeader(ds
, inData
, length
, outData
, pErrorCode
);
837 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
841 /* check data format and format version */
842 pInfo
=(const UDataInfo
*)((const char *)inData
+4);
844 pInfo
->dataFormat
[0]==0x53 && /* dataFormat="SPRP" */
845 pInfo
->dataFormat
[1]==0x50 &&
846 pInfo
->dataFormat
[2]==0x52 &&
847 pInfo
->dataFormat
[3]==0x50 &&
848 pInfo
->formatVersion
[0]==3
850 udata_printError(ds
, "usprep_swap(): data format %02x.%02x.%02x.%02x (format version %02x) is not recognized as StringPrep .spp data\n",
851 pInfo
->dataFormat
[0], pInfo
->dataFormat
[1],
852 pInfo
->dataFormat
[2], pInfo
->dataFormat
[3],
853 pInfo
->formatVersion
[0]);
854 *pErrorCode
=U_UNSUPPORTED_ERROR
;
858 inBytes
=(const uint8_t *)inData
+headerSize
;
859 outBytes
=(uint8_t *)outData
+headerSize
;
861 inIndexes
=(const int32_t *)inBytes
;
866 udata_printError(ds
, "usprep_swap(): too few bytes (%d after header) for StringPrep .spp data\n",
868 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
873 /* read the first 16 indexes (ICU 2.8/format version 3: _SPREP_INDEX_TOP==16, might grow) */
874 for(i
=0; i
<16; ++i
) {
875 indexes
[i
]=udata_readInt32(ds
, inIndexes
[i
]);
878 /* calculate the total length of the data */
880 16*4+ /* size of indexes[] */
881 indexes
[_SPREP_INDEX_TRIE_SIZE
]+
882 indexes
[_SPREP_INDEX_MAPPING_DATA_SIZE
];
886 udata_printError(ds
, "usprep_swap(): too few bytes (%d after header) for all of StringPrep .spp data\n",
888 *pErrorCode
=U_INDEX_OUTOFBOUNDS_ERROR
;
892 /* copy the data for inaccessible bytes */
893 if(inBytes
!=outBytes
) {
894 uprv_memcpy(outBytes
, inBytes
, size
);
899 /* swap the int32_t indexes[] */
901 ds
->swapArray32(ds
, inBytes
, count
, outBytes
, pErrorCode
);
905 count
=indexes
[_SPREP_INDEX_TRIE_SIZE
];
906 utrie_swap(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
909 /* swap the uint16_t mappingTable[] */
910 count
=indexes
[_SPREP_INDEX_MAPPING_DATA_SIZE
];
911 ds
->swapArray16(ds
, inBytes
+offset
, count
, outBytes
+offset
, pErrorCode
);
915 return headerSize
+size
;
918 #endif /* #if !UCONFIG_NO_IDNA */