]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/usprep.cpp
ICU-8.11.4.tar.gz
[apple/icu.git] / icuSources / common / usprep.cpp
1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 2003-2006, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 * file name: usprep.cpp
9 * encoding: US-ASCII
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * created on: 2003jul2
14 * created by: Ram Viswanadha
15 */
16
17 #include "unicode/utypes.h"
18
19 #if !UCONFIG_NO_IDNA
20
21 #include "unicode/usprep.h"
22
23 #include "unicode/unorm.h"
24 #include "unicode/ustring.h"
25 #include "unicode/uchar.h"
26 #include "unicode/uversion.h"
27 #include "umutex.h"
28 #include "cmemory.h"
29 #include "sprpimpl.h"
30 #include "ustr_imp.h"
31 #include "uhash.h"
32 #include "cstring.h"
33 #include "udataswp.h"
34 #include "ucln_cmn.h"
35 #include "unormimp.h"
36 #include "ubidi_props.h"
37
38 U_CDECL_BEGIN
39
40 /*
41 Static cache for already opened StringPrep profiles
42 */
43 static UHashtable *SHARED_DATA_HASHTABLE = NULL;
44
45 static UMTX usprepMutex = NULL;
46
47 /* format version of spp file */
48 static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
49
50 /* the Unicode version of the sprep data */
51 static UVersionInfo dataVersion={ 0, 0, 0, 0 };
52
53 static UBool U_CALLCONV
54 isSPrepAcceptable(void * /* context */,
55 const char * /* type */,
56 const char * /* name */,
57 const UDataInfo *pInfo) {
58 if(
59 pInfo->size>=20 &&
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
69 ) {
70 uprv_memcpy(formatVersion, pInfo->formatVersion, 4);
71 uprv_memcpy(dataVersion, pInfo->dataVersion, 4);
72 return TRUE;
73 } else {
74 return FALSE;
75 }
76 }
77
78 static int32_t U_CALLCONV
79 getSPrepFoldingOffset(uint32_t data) {
80
81 return (int32_t)data;
82
83 }
84
85 /* hashes an entry */
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);
93 }
94
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)));
107 }
108
109 static void
110 usprep_unload(UStringPrepProfile* data){
111 udata_close(data->sprepData);
112 }
113
114 static int32_t
115 usprep_internal_flushCache(UBool noRefCount){
116 UStringPrepProfile *profile = NULL;
117 UStringPrepKey *key = NULL;
118 int32_t pos = -1;
119 int32_t deletedNum = 0;
120 const UHashElement *e;
121
122 /*
123 * if shared data hasn't even been lazy evaluated yet
124 * return 0
125 */
126 umtx_lock(&usprepMutex);
127 if (SHARED_DATA_HASHTABLE == NULL) {
128 umtx_unlock(&usprepMutex);
129 return 0;
130 }
131
132 /*creates an enumeration to iterate through every element in the table */
133 while ((e = uhash_nextElement(SHARED_DATA_HASHTABLE, &pos)) != NULL)
134 {
135 profile = (UStringPrepProfile *) e->value.pointer;
136 key = (UStringPrepKey *) e->key.pointer;
137
138 if ((noRefCount== FALSE && profile->refCount == 0) ||
139 noRefCount== TRUE) {
140 deletedNum++;
141 uhash_removeElement(SHARED_DATA_HASHTABLE, e);
142
143 /* unload the data */
144 usprep_unload(profile);
145
146 if(key->name != NULL) {
147 uprv_free(key->name);
148 key->name=NULL;
149 }
150 if(key->path != NULL) {
151 uprv_free(key->path);
152 key->path=NULL;
153 }
154 uprv_free(profile);
155 uprv_free(key);
156 }
157
158 }
159 umtx_unlock(&usprepMutex);
160
161 return deletedNum;
162 }
163
164 /* Works just like ucnv_flushCache()
165 static int32_t
166 usprep_flushCache(){
167 return usprep_internal_flushCache(FALSE);
168 }
169 */
170
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;
177 }
178 }
179
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);
184 }
185 U_CDECL_END
186
187 static void
188 usprep_init() {
189 umtx_init(&usprepMutex);
190 }
191
192 /** Initializes the cache for resources */
193 static void
194 initCache(UErrorCode *status) {
195 UBool makeCache = FALSE;
196 umtx_lock(&usprepMutex);
197 makeCache = (SHARED_DATA_HASHTABLE == NULL);
198 umtx_unlock(&usprepMutex);
199 if(makeCache) {
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);
206 newCache = NULL;
207 }
208 umtx_unlock(&usprepMutex);
209 if(newCache != NULL) {
210 uhash_close(newCache);
211 }
212 }
213 }
214 }
215
216 static UBool U_CALLCONV
217 loadData(UStringPrepProfile* profile,
218 const char* path,
219 const char* name,
220 const char* type,
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;
226 const uint8_t *pb;
227 UVersionInfo normUnicodeVersion;
228 int32_t normUniVer, sprepUniVer, normCorrVer;
229
230 if(errorCode==NULL || U_FAILURE(*errorCode)) {
231 return 0;
232 }
233
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)) {
238 return FALSE;
239 }
240
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;
245
246
247 if(U_FAILURE(*errorCode)) {
248 udata_close(dataMemory);
249 return FALSE;
250 }
251
252 /* in the mutex block, set the data for this process */
253 umtx_lock(&usprepMutex);
254 if(profile->sprepData==NULL) {
255 profile->sprepData=dataMemory;
256 dataMemory=NULL;
257 uprv_memcpy(&profile->indexes, p, sizeof(profile->indexes));
258 uprv_memcpy(&profile->sprepTrie, &_sprepTrie, sizeof(UTrie));
259 } else {
260 p=(const int32_t *)udata_getMemory(profile->sprepData);
261 }
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]);
265
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];
272
273 if(U_FAILURE(*errorCode)){
274 udata_close(dataMemory);
275 return FALSE;
276 }
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*/
280 ){
281 *errorCode = U_INVALID_FORMAT_ERROR;
282 udata_close(dataMemory);
283 return FALSE;
284 }
285 profile->isDataLoaded = TRUE;
286
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 */
290 }
291
292
293 return profile->isDataLoaded;
294 }
295
296 static UStringPrepProfile*
297 usprep_getProfile(const char* path,
298 const char* name,
299 UErrorCode *status){
300
301 UStringPrepProfile* profile = NULL;
302
303 initCache(status);
304
305 if(U_FAILURE(*status)){
306 return NULL;
307 }
308
309 UStringPrepKey stackKey;
310 /*
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
314 */
315 stackKey.name = (char*) name;
316 stackKey.path = (char*) path;
317
318 /* fetch the data from the cache */
319 umtx_lock(&usprepMutex);
320 profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
321 umtx_unlock(&usprepMutex);
322
323 if(profile == NULL){
324 UStringPrepKey* key = (UStringPrepKey*) uprv_malloc(sizeof(UStringPrepKey));
325 if(key == NULL){
326 *status = U_MEMORY_ALLOCATION_ERROR;
327 return NULL;
328 }
329 /* else load the data and put the data in the cache */
330 profile = (UStringPrepProfile*) uprv_malloc(sizeof(UStringPrepProfile));
331 if(profile == NULL){
332 *status = U_MEMORY_ALLOCATION_ERROR;
333 uprv_free(key);
334 return NULL;
335 }
336
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;
342
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;
347 uprv_free(key);
348 uprv_free(profile);
349 return NULL;
350 }
351
352 uprv_strcpy(key->name, name);
353
354 key->path=NULL;
355
356 if(path != NULL){
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);
361 uprv_free(key);
362 uprv_free(profile);
363 return NULL;
364 }
365 uprv_strcpy(key->path, path);
366 }
367
368 /* load the data */
369 if(!loadData(profile, path, name, _SPREP_DATA_TYPE, status) || U_FAILURE(*status) ){
370 uprv_free(key->path);
371 uprv_free(key->name);
372 uprv_free(key);
373 uprv_free(profile);
374 return NULL;
375 }
376
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);
380
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);
387 uprv_free(key);
388 uprv_free(profile);
389 return NULL;
390 }
391 } else {
392 profile->bdp = NULL;
393 }
394
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);
399 }
400 umtx_lock(&usprepMutex);
401 /* increment the refcount */
402 profile->refCount++;
403 umtx_unlock(&usprepMutex);
404
405 return profile;
406 }
407
408 U_CAPI UStringPrepProfile* U_EXPORT2
409 usprep_open(const char* path,
410 const char* name,
411 UErrorCode* status){
412
413 if(status == NULL || U_FAILURE(*status)){
414 return NULL;
415 }
416 /* initialize the mutex */
417 usprep_init();
418
419 /* initialize the profile struct members */
420 return usprep_getProfile(path,name,status);
421 }
422
423 U_CAPI void U_EXPORT2
424 usprep_close(UStringPrepProfile* profile){
425 if(profile==NULL){
426 return;
427 }
428
429 umtx_lock(&usprepMutex);
430 /* decrement the ref count*/
431 if(profile->refCount > 0){
432 profile->refCount--;
433 }
434 umtx_unlock(&usprepMutex);
435
436 }
437
438 U_CFUNC void
439 uprv_syntaxError(const UChar* rules,
440 int32_t pos,
441 int32_t rulesLen,
442 UParseError* parseError){
443 if(parseError == NULL){
444 return;
445 }
446 parseError->offset = pos;
447 parseError->line = 0 ; // we are not using line numbers
448
449 // for pre-context
450 int32_t start = (pos <=U_PARSE_CONTEXT_LEN)? 0 : (pos - (U_PARSE_CONTEXT_LEN-1));
451 int32_t limit = pos;
452
453 u_memcpy(parseError->preContext,rules+start,limit-start);
454 //null terminate the buffer
455 parseError->preContext[limit-start] = 0;
456
457 // for post-context; include error rules[pos]
458 start = pos;
459 limit = start + (U_PARSE_CONTEXT_LEN-1);
460 if (limit > rulesLen) {
461 limit = rulesLen;
462 }
463 if (start < rulesLen) {
464 u_memcpy(parseError->postContext,rules+start,limit-start);
465 }
466 //null terminate the buffer
467 parseError->postContext[limit-start]= 0;
468 }
469
470
471 static inline UStringPrepType
472 getValues(uint16_t trieWord, int16_t& value, UBool& isIndex){
473
474 UStringPrepType type;
475 if(trieWord == 0){
476 /*
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
480 */
481 type = USPREP_TYPE_LIMIT;
482 isIndex =FALSE;
483 value = 0;
484 }else if(trieWord >= _SPREP_TYPE_THRESHOLD){
485 type = (UStringPrepType) (trieWord - _SPREP_TYPE_THRESHOLD);
486 isIndex =FALSE;
487 value = 0;
488 }else{
489 /* get the type */
490 type = USPREP_MAP;
491 /* ascertain if the value is index or delta */
492 if(trieWord & 0x02){
493 isIndex = TRUE;
494 value = trieWord >> 2; //mask off the lower 2 bits and shift
495 }else{
496 isIndex = FALSE;
497 value = (int16_t)trieWord;
498 value = (value >> 2);
499 }
500
501 if((trieWord>>2) == _SPREP_MAX_INDEX_VALUE){
502 type = USPREP_DELETE;
503 isIndex =FALSE;
504 value = 0;
505 }
506 }
507 return type;
508 }
509
510
511
512 static int32_t
513 usprep_map( const UStringPrepProfile* profile,
514 const UChar* src, int32_t srcLength,
515 UChar* dest, int32_t destCapacity,
516 int32_t options,
517 UParseError* parseError,
518 UErrorCode* status ){
519
520 uint16_t result;
521 int32_t destIndex=0;
522 int32_t srcIndex;
523 UBool allowUnassigned = (UBool) ((options & USPREP_ALLOW_UNASSIGNED)>0);
524 UStringPrepType type;
525 int16_t value;
526 UBool isIndex;
527 const int32_t* indexes = profile->indexes;
528
529 // no error checking the caller check for error and arguments
530 // no string length check the caller finds out the string length
531
532 for(srcIndex=0;srcIndex<srcLength;){
533 UChar32 ch;
534
535 U16_NEXT(src,srcIndex,srcLength,ch);
536
537 result=0;
538
539 UTRIE_GET16(&profile->sprepTrie,ch,result);
540
541 type = getValues(result, value, isIndex);
542
543 // check if the source codepoint is unassigned
544 if(type == USPREP_UNASSIGNED && allowUnassigned == FALSE){
545
546 uprv_syntaxError(src,srcIndex-U16_LENGTH(ch), srcLength,parseError);
547 *status = U_STRINGPREP_UNASSIGNED_ERROR;
548 return 0;
549
550 }else if(type == USPREP_MAP){
551
552 int32_t index, length;
553
554 if(isIndex){
555 index = value;
556 if(index >= indexes[_SPREP_ONE_UCHAR_MAPPING_INDEX_START] &&
557 index < indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START]){
558 length = 1;
559 }else if(index >= indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START] &&
560 index < indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START]){
561 length = 2;
562 }else if(index >= indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START] &&
563 index < indexes[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START]){
564 length = 3;
565 }else{
566 length = profile->mappingData[index++];
567
568 }
569
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];
574 }
575 destIndex++; /* for pre-flighting */
576 }
577 continue;
578 }else{
579 // subtract the delta to arrive at the code point
580 ch -= value;
581 }
582
583 }else if(type==USPREP_DELETE){
584 // just consume the codepoint and contine
585 continue;
586 }
587 //copy the code point into destination
588 if(ch <= 0xFFFF){
589 if(destIndex < destCapacity ){
590 dest[destIndex] = (UChar)ch;
591 }
592 destIndex++;
593 }else{
594 if(destIndex+1 < destCapacity ){
595 dest[destIndex] = U16_LEAD(ch);
596 dest[destIndex+1] = U16_TRAIL(ch);
597 }
598 destIndex +=2;
599 }
600
601 }
602
603 return u_terminateUChars(dest, destCapacity, destIndex, status);
604 }
605
606
607 static int32_t
608 usprep_normalize( const UChar* src, int32_t srcLength,
609 UChar* dest, int32_t destCapacity,
610 UErrorCode* status ){
611 /*
612 * Option UNORM_BEFORE_PRI_29:
613 *
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
621 */
622 return unorm_normalize(
623 src, srcLength,
624 UNORM_NFKC, UNORM_UNICODE_3_2|UNORM_BEFORE_PRI_29,
625 dest, destCapacity,
626 status);
627 }
628
629
630 /*
631 1) Map -- For each character in the input, check if it has a mapping
632 and, if so, replace it with its mapping.
633
634 2) Normalize -- Possibly normalize the result of step 1 using Unicode
635 normalization.
636
637 3) Prohibit -- Check for any characters that are not allowed in the
638 output. If any are found, return an error.
639
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
644 error.
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
650
651
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".
655
656 In any profile that specifies bidirectional character handling, all
657 three of the following requirements MUST be met:
658
659 1) The characters in section 5.8 MUST be prohibited.
660
661 2) If a string contains any RandALCat character, the string MUST NOT
662 contain any LCat character.
663
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.
667 */
668
669 #define MAX_STACK_BUFFER_SIZE 300
670
671
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,
676 int32_t options,
677 UParseError* parseError,
678 UErrorCode* status ){
679
680 // check error status
681 if(status == NULL || U_FAILURE(*status)){
682 return 0;
683 }
684
685 //check arguments
686 if(profile==NULL || src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
687 *status=U_ILLEGAL_ARGUMENT_ERROR;
688 return 0;
689 }
690
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;
696 uint16_t result;
697 int32_t b2Index = 0;
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;
701
702 //get the string length
703 if(srcLength == -1){
704 srcLength = u_strlen(src);
705 }
706 // map
707 b1Len = usprep_map(profile, src, srcLength, b1, b1Capacity, options, parseError, status);
708
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);
713 if(b1==NULL){
714 *status = U_MEMORY_ALLOCATION_ERROR;
715 goto CLEANUP;
716 }
717
718 *status = U_ZERO_ERROR; // reset error
719
720 b1Len = usprep_map(profile, src, srcLength, b1, b1Len, options, parseError, status);
721
722 }
723
724 // normalize
725 if(profile->doNFKC == TRUE){
726 b2Len = usprep_normalize(b1,b1Len, b2,b2Capacity,status);
727
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);
732 if(b2==NULL){
733 *status = U_MEMORY_ALLOCATION_ERROR;
734 goto CLEANUP;
735 }
736
737 *status = U_ZERO_ERROR; // reset error
738
739 b2Len = usprep_normalize(b1,b1Len, b2,b2Len,status);
740
741 }
742
743 }else{
744 b2 = b1;
745 b2Len = b1Len;
746 }
747
748
749 if(U_FAILURE(*status)){
750 goto CLEANUP;
751 }
752
753 UChar32 ch;
754 UStringPrepType type;
755 int16_t value;
756 UBool isIndex;
757
758 // Prohibit and checkBiDi in one pass
759 for(b2Index=0; b2Index<b2Len;){
760
761 ch = 0;
762
763 U16_NEXT(b2, b2Index, b2Len, ch);
764
765 UTRIE_GET16(&profile->sprepTrie,ch,result);
766
767 type = getValues(result, value, isIndex);
768
769 if( type == USPREP_PROHIBITED ||
770 ((result < _SPREP_TYPE_THRESHOLD) && (result & 0x01) /* first bit says it the code point is prohibited*/)
771 ){
772 *status = U_STRINGPREP_PROHIBITED_ERROR;
773 uprv_syntaxError(b1, b2Index-U16_LENGTH(ch), b2Len, parseError);
774 goto CLEANUP;
775 }
776
777 if(profile->checkBiDi) {
778 direction = ubidi_getClass(profile->bdp, ch);
779 if(firstCharDir == U_CHAR_DIRECTION_COUNT){
780 firstCharDir = direction;
781 }
782 if(direction == U_LEFT_TO_RIGHT){
783 leftToRight = TRUE;
784 ltrPos = b2Index-1;
785 }
786 if(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC){
787 rightToLeft = TRUE;
788 rtlPos = b2Index-1;
789 }
790 }
791 }
792 if(profile->checkBiDi == TRUE){
793 // satisfy 2
794 if( leftToRight == TRUE && rightToLeft == TRUE){
795 *status = U_STRINGPREP_CHECK_BIDI_ERROR;
796 uprv_syntaxError(b2,(rtlPos>ltrPos) ? rtlPos : ltrPos, b2Len, parseError);
797 goto CLEANUP;
798 }
799
800 //satisfy 3
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))
804 ){
805 *status = U_STRINGPREP_CHECK_BIDI_ERROR;
806 uprv_syntaxError(b2, rtlPos, b2Len, parseError);
807 return FALSE;
808 }
809 }
810 if(b2Len>0 && b2Len <= destCapacity){
811 uprv_memmove(dest,b2, b2Len*U_SIZEOF_UCHAR);
812 }
813
814 CLEANUP:
815 if(b1!=b1Stack){
816 uprv_free(b1);
817 b1=NULL;
818 }
819
820 if(b2!=b1Stack && b2!=b2Stack && b2!=b1 /* b1 should not be freed twice */){
821 uprv_free(b2);
822 b2=NULL;
823 }
824 return u_terminateUChars(dest, destCapacity, b2Len, status);
825 }
826
827
828 /* data swapping ------------------------------------------------------------ */
829
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;
835 int32_t headerSize;
836
837 const uint8_t *inBytes;
838 uint8_t *outBytes;
839
840 const int32_t *inIndexes;
841 int32_t indexes[16];
842
843 int32_t i, offset, count, size;
844
845 /* udata_swapDataHeader checks the arguments */
846 headerSize=udata_swapDataHeader(ds, inData, length, outData, pErrorCode);
847 if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
848 return 0;
849 }
850
851 /* check data format and format version */
852 pInfo=(const UDataInfo *)((const char *)inData+4);
853 if(!(
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
859 )) {
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;
865 return 0;
866 }
867
868 inBytes=(const uint8_t *)inData+headerSize;
869 outBytes=(uint8_t *)outData+headerSize;
870
871 inIndexes=(const int32_t *)inBytes;
872
873 if(length>=0) {
874 length-=headerSize;
875 if(length<16*4) {
876 udata_printError(ds, "usprep_swap(): too few bytes (%d after header) for StringPrep .spp data\n",
877 length);
878 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
879 return 0;
880 }
881 }
882
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]);
886 }
887
888 /* calculate the total length of the data */
889 size=
890 16*4+ /* size of indexes[] */
891 indexes[_SPREP_INDEX_TRIE_SIZE]+
892 indexes[_SPREP_INDEX_MAPPING_DATA_SIZE];
893
894 if(length>=0) {
895 if(length<size) {
896 udata_printError(ds, "usprep_swap(): too few bytes (%d after header) for all of StringPrep .spp data\n",
897 length);
898 *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR;
899 return 0;
900 }
901
902 /* copy the data for inaccessible bytes */
903 if(inBytes!=outBytes) {
904 uprv_memcpy(outBytes, inBytes, size);
905 }
906
907 offset=0;
908
909 /* swap the int32_t indexes[] */
910 count=16*4;
911 ds->swapArray32(ds, inBytes, count, outBytes, pErrorCode);
912 offset+=count;
913
914 /* swap the UTrie */
915 count=indexes[_SPREP_INDEX_TRIE_SIZE];
916 utrie_swap(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
917 offset+=count;
918
919 /* swap the uint16_t mappingTable[] */
920 count=indexes[_SPREP_INDEX_MAPPING_DATA_SIZE];
921 ds->swapArray16(ds, inBytes+offset, count, outBytes+offset, pErrorCode);
922 offset+=count;
923 }
924
925 return headerSize+size;
926 }
927
928 #endif /* #if !UCONFIG_NO_IDNA */