• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *******************************************************************************
3  *
4  *   Copyright (C) 2003-2014, International Business Machines
5  *   Corporation and others.  All Rights Reserved.
6  *
7  *******************************************************************************
8  *   file name:  uidna.cpp
9  *   encoding:   US-ASCII
10  *   tab size:   8 (not used)
11  *   indentation:4
12  *
13  *   created on: 2003feb1
14  *   created by: Ram Viswanadha
15  */
16 
17 #include "unicode/utypes.h"
18 
19 #if !UCONFIG_NO_IDNA
20 
21 #include "unicode/uidna.h"
22 #include "unicode/ustring.h"
23 #include "unicode/usprep.h"
24 #include "punycode.h"
25 #include "ustr_imp.h"
26 #include "cmemory.h"
27 #include "uassert.h"
28 #include "sprpimpl.h"
29 
30 /* it is official IDNA ACE Prefix is "xn--" */
31 static const UChar ACE_PREFIX[] ={ 0x0078,0x006E,0x002d,0x002d } ;
32 #define ACE_PREFIX_LENGTH 4
33 
34 #define MAX_LABEL_LENGTH 63
35 /* The Max length of the labels should not be more than MAX_LABEL_LENGTH */
36 #define MAX_LABEL_BUFFER_SIZE 100
37 
38 #define MAX_DOMAIN_NAME_LENGTH 255
39 /* The Max length of the domain names should not be more than MAX_DOMAIN_NAME_LENGTH */
40 #define MAX_IDN_BUFFER_SIZE   MAX_DOMAIN_NAME_LENGTH+1
41 
42 #define LOWER_CASE_DELTA 0x0020
43 #define HYPHEN           0x002D
44 #define FULL_STOP        0x002E
45 #define CAPITAL_A        0x0041
46 #define CAPITAL_Z        0x005A
47 
48 inline static UChar
toASCIILower(UChar ch)49 toASCIILower(UChar ch){
50     if(CAPITAL_A <= ch && ch <= CAPITAL_Z){
51         return ch + LOWER_CASE_DELTA;
52     }
53     return ch;
54 }
55 
56 inline static UBool
startsWithPrefix(const UChar * src,int32_t srcLength)57 startsWithPrefix(const UChar* src , int32_t srcLength){
58     UBool startsWithPrefix = TRUE;
59 
60     if(srcLength < ACE_PREFIX_LENGTH){
61         return FALSE;
62     }
63 
64     for(int8_t i=0; i< ACE_PREFIX_LENGTH; i++){
65         if(toASCIILower(src[i]) != ACE_PREFIX[i]){
66             startsWithPrefix = FALSE;
67         }
68     }
69     return startsWithPrefix;
70 }
71 
72 
73 inline static int32_t
compareCaseInsensitiveASCII(const UChar * s1,int32_t s1Len,const UChar * s2,int32_t s2Len)74 compareCaseInsensitiveASCII(const UChar* s1, int32_t s1Len,
75                             const UChar* s2, int32_t s2Len){
76 
77     int32_t minLength;
78     int32_t lengthResult;
79 
80     // are we comparing different lengths?
81     if(s1Len != s2Len) {
82         if(s1Len < s2Len) {
83             minLength = s1Len;
84             lengthResult = -1;
85         } else {
86             minLength = s2Len;
87             lengthResult = 1;
88         }
89     } else {
90         // ok the lengths are equal
91         minLength = s1Len;
92         lengthResult = 0;
93     }
94 
95     UChar c1,c2;
96     int32_t rc;
97 
98     for(int32_t i =0;/* no condition */;i++) {
99 
100         /* If we reach the ends of both strings then they match */
101         if(i == minLength) {
102             return lengthResult;
103         }
104 
105         c1 = s1[i];
106         c2 = s2[i];
107 
108         /* Case-insensitive comparison */
109         if(c1!=c2) {
110             rc=(int32_t)toASCIILower(c1)-(int32_t)toASCIILower(c2);
111             if(rc!=0) {
112                 lengthResult=rc;
113                 break;
114             }
115         }
116     }
117     return lengthResult;
118 }
119 
120 
121 /**
122  * Ascertain if the given code point is a label separator as
123  * defined by the IDNA RFC
124  *
125  * @param ch The code point to be ascertained
126  * @return true if the char is a label separator
127  * @stable ICU 2.8
128  */
isLabelSeparator(UChar ch)129 static inline UBool isLabelSeparator(UChar ch){
130     switch(ch){
131         case 0x002e:
132         case 0x3002:
133         case 0xFF0E:
134         case 0xFF61:
135             return TRUE;
136         default:
137             return FALSE;
138     }
139 }
140 
141 // returns the length of the label excluding the separator
142 // if *limit == separator then the length returned does not include
143 // the separtor.
144 static inline int32_t
getNextSeparator(UChar * src,int32_t srcLength,UChar ** limit,UBool * done)145 getNextSeparator(UChar *src, int32_t srcLength,
146                  UChar **limit, UBool *done){
147     if(srcLength == -1){
148         int32_t i;
149         for(i=0 ; ;i++){
150             if(src[i] == 0){
151                 *limit = src + i; // point to null
152                 *done = TRUE;
153                 return i;
154             }
155             if(isLabelSeparator(src[i])){
156                 *limit = src + (i+1); // go past the delimiter
157                 return i;
158 
159             }
160         }
161     }else{
162         int32_t i;
163         for(i=0;i<srcLength;i++){
164             if(isLabelSeparator(src[i])){
165                 *limit = src + (i+1); // go past the delimiter
166                 return i;
167             }
168         }
169         // we have not found the delimiter
170         // if(i==srcLength)
171         *limit = src+srcLength;
172         *done = TRUE;
173 
174         return i;
175     }
176 }
isLDHChar(UChar ch)177 static inline UBool isLDHChar(UChar ch){
178     // high runner case
179     if(ch>0x007A){
180         return FALSE;
181     }
182     //[\\u002D \\u0030-\\u0039 \\u0041-\\u005A \\u0061-\\u007A]
183     if( (ch==0x002D) ||
184         (0x0030 <= ch && ch <= 0x0039) ||
185         (0x0041 <= ch && ch <= 0x005A) ||
186         (0x0061 <= ch && ch <= 0x007A)
187       ){
188         return TRUE;
189     }
190     return FALSE;
191 }
192 
193 static int32_t
_internal_toASCII(const UChar * src,int32_t srcLength,UChar * dest,int32_t destCapacity,int32_t options,UStringPrepProfile * nameprep,UParseError * parseError,UErrorCode * status)194 _internal_toASCII(const UChar* src, int32_t srcLength,
195                   UChar* dest, int32_t destCapacity,
196                   int32_t options,
197                   UStringPrepProfile* nameprep,
198                   UParseError* parseError,
199                   UErrorCode* status)
200 {
201 
202     // TODO Revisit buffer handling. The label should not be over 63 ASCII characters. ICU4J may need to be updated too.
203     UChar b1Stack[MAX_LABEL_BUFFER_SIZE], b2Stack[MAX_LABEL_BUFFER_SIZE];
204     //initialize pointers to stack buffers
205     UChar  *b1 = b1Stack, *b2 = b2Stack;
206     int32_t b1Len=0, b2Len,
207             b1Capacity = MAX_LABEL_BUFFER_SIZE,
208             b2Capacity = MAX_LABEL_BUFFER_SIZE ,
209             reqLength=0;
210 
211     int32_t namePrepOptions = ((options & UIDNA_ALLOW_UNASSIGNED) != 0) ? USPREP_ALLOW_UNASSIGNED: 0;
212     UBool* caseFlags = NULL;
213 
214     // the source contains all ascii codepoints
215     UBool srcIsASCII  = TRUE;
216     // assume the source contains all LDH codepoints
217     UBool srcIsLDH = TRUE;
218 
219     int32_t j=0;
220 
221     //get the options
222     UBool useSTD3ASCIIRules = (UBool)((options & UIDNA_USE_STD3_RULES) != 0);
223 
224     int32_t failPos = -1;
225 
226     if(srcLength == -1){
227         srcLength = u_strlen(src);
228     }
229 
230     if(srcLength > b1Capacity){
231         b1 = (UChar*) uprv_malloc(srcLength * U_SIZEOF_UCHAR);
232         if(b1==NULL){
233             *status = U_MEMORY_ALLOCATION_ERROR;
234             goto CLEANUP;
235         }
236         b1Capacity = srcLength;
237     }
238 
239     // step 1
240     for( j=0;j<srcLength;j++){
241         if(src[j] > 0x7F){
242             srcIsASCII = FALSE;
243         }
244         b1[b1Len++] = src[j];
245     }
246 
247     // step 2 is performed only if the source contains non ASCII
248     if(srcIsASCII == FALSE){
249 
250         // step 2
251         b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Capacity, namePrepOptions, parseError, status);
252 
253         if(*status == U_BUFFER_OVERFLOW_ERROR){
254             // redo processing of string
255             // we do not have enough room so grow the buffer
256             if(b1 != b1Stack){
257                 uprv_free(b1);
258             }
259             b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
260             if(b1==NULL){
261                 *status = U_MEMORY_ALLOCATION_ERROR;
262                 goto CLEANUP;
263             }
264 
265             *status = U_ZERO_ERROR; // reset error
266 
267             b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Len, namePrepOptions, parseError, status);
268         }
269     }
270     // error bail out
271     if(U_FAILURE(*status)){
272         goto CLEANUP;
273     }
274     if(b1Len == 0){
275         *status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
276         goto CLEANUP;
277     }
278 
279     // for step 3 & 4
280     srcIsASCII = TRUE;
281     for( j=0;j<b1Len;j++){
282         // check if output of usprep_prepare is all ASCII
283         if(b1[j] > 0x7F){
284             srcIsASCII = FALSE;
285         }else if(isLDHChar(b1[j])==FALSE){  // if the char is in ASCII range verify that it is an LDH character
286             srcIsLDH = FALSE;
287             failPos = j;
288         }
289     }
290     if(useSTD3ASCIIRules == TRUE){
291         // verify 3a and 3b
292         // 3(a) Verify the absence of non-LDH ASCII code points; that is, the
293         //  absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
294         // 3(b) Verify the absence of leading and trailing hyphen-minus; that
295         //  is, the absence of U+002D at the beginning and end of the
296         //  sequence.
297         if( srcIsLDH == FALSE /* source at this point should not contain anyLDH characters */
298             || b1[0] ==  HYPHEN || b1[b1Len-1] == HYPHEN){
299             *status = U_IDNA_STD3_ASCII_RULES_ERROR;
300 
301             /* populate the parseError struct */
302             if(srcIsLDH==FALSE){
303                 // failPos is always set the index of failure
304                 uprv_syntaxError(b1,failPos, b1Len,parseError);
305             }else if(b1[0] == HYPHEN){
306                 // fail position is 0
307                 uprv_syntaxError(b1,0,b1Len,parseError);
308             }else{
309                 // the last index in the source is always length-1
310                 uprv_syntaxError(b1, (b1Len>0) ? b1Len-1 : b1Len, b1Len,parseError);
311             }
312 
313             goto CLEANUP;
314         }
315     }
316     // Step 4: if the source is ASCII then proceed to step 8
317     if(srcIsASCII){
318         if(b1Len <= destCapacity){
319             uprv_memmove(dest, b1, b1Len * U_SIZEOF_UCHAR);
320             reqLength = b1Len;
321         }else{
322             reqLength = b1Len;
323             goto CLEANUP;
324         }
325     }else{
326         // step 5 : verify the sequence does not begin with ACE prefix
327         if(!startsWithPrefix(b1,b1Len)){
328 
329             //step 6: encode the sequence with punycode
330 
331             // do not preserve the case flags for now!
332             // TODO: Preserve the case while implementing the RFE
333             // caseFlags = (UBool*) uprv_malloc(b1Len * sizeof(UBool));
334             // uprv_memset(caseFlags,TRUE,b1Len);
335 
336             b2Len = u_strToPunycode(b1,b1Len,b2,b2Capacity,caseFlags, status);
337 
338             if(*status == U_BUFFER_OVERFLOW_ERROR){
339                 // redo processing of string
340                 /* we do not have enough room so grow the buffer*/
341                 b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
342                 if(b2 == NULL){
343                     *status = U_MEMORY_ALLOCATION_ERROR;
344                     goto CLEANUP;
345                 }
346 
347                 *status = U_ZERO_ERROR; // reset error
348 
349                 b2Len = u_strToPunycode(b1,b1Len,b2,b2Len,caseFlags, status);
350             }
351             //error bail out
352             if(U_FAILURE(*status)){
353                 goto CLEANUP;
354             }
355             // TODO : Reconsider while implementing the case preserve RFE
356             // convert all codepoints to lower case ASCII
357             // toASCIILower(b2,b2Len);
358             reqLength = b2Len+ACE_PREFIX_LENGTH;
359 
360             if(reqLength > destCapacity){
361                 *status = U_BUFFER_OVERFLOW_ERROR;
362                 goto CLEANUP;
363             }
364             //Step 7: prepend the ACE prefix
365             uprv_memcpy(dest,ACE_PREFIX,ACE_PREFIX_LENGTH * U_SIZEOF_UCHAR);
366             //Step 6: copy the contents in b2 into dest
367             uprv_memcpy(dest+ACE_PREFIX_LENGTH, b2, b2Len * U_SIZEOF_UCHAR);
368 
369         }else{
370             *status = U_IDNA_ACE_PREFIX_ERROR;
371             //position of failure is 0
372             uprv_syntaxError(b1,0,b1Len,parseError);
373             goto CLEANUP;
374         }
375     }
376     // step 8: verify the length of label
377     if(reqLength > MAX_LABEL_LENGTH){
378         *status = U_IDNA_LABEL_TOO_LONG_ERROR;
379     }
380 
381 CLEANUP:
382     if(b1 != b1Stack){
383         uprv_free(b1);
384     }
385     if(b2 != b2Stack){
386         uprv_free(b2);
387     }
388     uprv_free(caseFlags);
389 
390     return u_terminateUChars(dest, destCapacity, reqLength, status);
391 }
392 
393 static int32_t
_internal_toUnicode(const UChar * src,int32_t srcLength,UChar * dest,int32_t destCapacity,int32_t options,UStringPrepProfile * nameprep,UParseError * parseError,UErrorCode * status)394 _internal_toUnicode(const UChar* src, int32_t srcLength,
395                     UChar* dest, int32_t destCapacity,
396                     int32_t options,
397                     UStringPrepProfile* nameprep,
398                     UParseError* parseError,
399                     UErrorCode* status)
400 {
401 
402     //get the options
403     //UBool useSTD3ASCIIRules = (UBool)((options & UIDNA_USE_STD3_RULES) != 0);
404     int32_t namePrepOptions = ((options & UIDNA_ALLOW_UNASSIGNED) != 0) ? USPREP_ALLOW_UNASSIGNED: 0;
405 
406     // TODO Revisit buffer handling. The label should not be over 63 ASCII characters. ICU4J may need to be updated too.
407     UChar b1Stack[MAX_LABEL_BUFFER_SIZE], b2Stack[MAX_LABEL_BUFFER_SIZE], b3Stack[MAX_LABEL_BUFFER_SIZE];
408 
409     //initialize pointers to stack buffers
410     UChar  *b1 = b1Stack, *b2 = b2Stack, *b1Prime=NULL, *b3=b3Stack;
411     int32_t b1Len = 0, b2Len, b1PrimeLen, b3Len,
412             b1Capacity = MAX_LABEL_BUFFER_SIZE,
413             b2Capacity = MAX_LABEL_BUFFER_SIZE,
414             b3Capacity = MAX_LABEL_BUFFER_SIZE,
415             reqLength=0;
416 
417     UBool* caseFlags = NULL;
418 
419     UBool srcIsASCII = TRUE;
420     /*UBool srcIsLDH = TRUE;
421     int32_t failPos =0;*/
422 
423     // step 1: find out if all the codepoints in src are ASCII
424     if(srcLength==-1){
425         srcLength = 0;
426         for(;src[srcLength]!=0;){
427             if(src[srcLength]> 0x7f){
428                 srcIsASCII = FALSE;
429             }/*else if(isLDHChar(src[srcLength])==FALSE){
430                 // here we do not assemble surrogates
431                 // since we know that LDH code points
432                 // are in the ASCII range only
433                 srcIsLDH = FALSE;
434                 failPos = srcLength;
435             }*/
436             srcLength++;
437         }
438     }else if(srcLength > 0){
439         for(int32_t j=0; j<srcLength; j++){
440             if(src[j]> 0x7f){
441                 srcIsASCII = FALSE;
442             }/*else if(isLDHChar(src[j])==FALSE){
443                 // here we do not assemble surrogates
444                 // since we know that LDH code points
445                 // are in the ASCII range only
446                 srcIsLDH = FALSE;
447                 failPos = j;
448             }*/
449         }
450     }else{
451         return 0;
452     }
453 
454     if(srcIsASCII == FALSE){
455         // step 2: process the string
456         b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Capacity, namePrepOptions, parseError, status);
457         if(*status == U_BUFFER_OVERFLOW_ERROR){
458             // redo processing of string
459             /* we do not have enough room so grow the buffer*/
460             b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
461             if(b1==NULL){
462                 *status = U_MEMORY_ALLOCATION_ERROR;
463                 goto CLEANUP;
464             }
465 
466             *status = U_ZERO_ERROR; // reset error
467 
468             b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Len, namePrepOptions, parseError, status);
469         }
470         //bail out on error
471         if(U_FAILURE(*status)){
472             goto CLEANUP;
473         }
474     }else{
475 
476         //just point src to b1
477         b1 = (UChar*) src;
478         b1Len = srcLength;
479     }
480 
481     // The RFC states that
482     // <quote>
483     // ToUnicode never fails. If any step fails, then the original input
484     // is returned immediately in that step.
485     // </quote>
486 
487     //step 3: verify ACE Prefix
488     if(startsWithPrefix(b1,b1Len)){
489 
490         //step 4: Remove the ACE Prefix
491         b1Prime = b1 + ACE_PREFIX_LENGTH;
492         b1PrimeLen  = b1Len - ACE_PREFIX_LENGTH;
493 
494         //step 5: Decode using punycode
495         b2Len = u_strFromPunycode(b1Prime, b1PrimeLen, b2, b2Capacity, caseFlags,status);
496 
497         if(*status == U_BUFFER_OVERFLOW_ERROR){
498             // redo processing of string
499             /* we do not have enough room so grow the buffer*/
500             b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
501             if(b2==NULL){
502                 *status = U_MEMORY_ALLOCATION_ERROR;
503                 goto CLEANUP;
504             }
505 
506             *status = U_ZERO_ERROR; // reset error
507 
508             b2Len =  u_strFromPunycode(b1Prime, b1PrimeLen, b2, b2Len, caseFlags, status);
509         }
510 
511 
512         //step 6:Apply toASCII
513         b3Len = uidna_toASCII(b2, b2Len, b3, b3Capacity, options, parseError, status);
514 
515         if(*status == U_BUFFER_OVERFLOW_ERROR){
516             // redo processing of string
517             /* we do not have enough room so grow the buffer*/
518             b3 = (UChar*) uprv_malloc(b3Len * U_SIZEOF_UCHAR);
519             if(b3==NULL){
520                 *status = U_MEMORY_ALLOCATION_ERROR;
521                 goto CLEANUP;
522             }
523 
524             *status = U_ZERO_ERROR; // reset error
525 
526             b3Len =  uidna_toASCII(b2,b2Len,b3,b3Len,options,parseError, status);
527 
528         }
529         //bail out on error
530         if(U_FAILURE(*status)){
531             goto CLEANUP;
532         }
533 
534         //step 7: verify
535         if(compareCaseInsensitiveASCII(b1, b1Len, b3, b3Len) !=0){
536             // Cause the original to be returned.
537             *status = U_IDNA_VERIFICATION_ERROR;
538             goto CLEANUP;
539         }
540 
541         //step 8: return output of step 5
542         reqLength = b2Len;
543         if(b2Len <= destCapacity) {
544             uprv_memmove(dest, b2, b2Len * U_SIZEOF_UCHAR);
545         }
546     }
547     else{
548         // See the start of this if statement for why this is commented out.
549         // verify that STD3 ASCII rules are satisfied
550         /*if(useSTD3ASCIIRules == TRUE){
551             if( srcIsLDH == FALSE // source contains some non-LDH characters
552                 || src[0] ==  HYPHEN || src[srcLength-1] == HYPHEN){
553                 *status = U_IDNA_STD3_ASCII_RULES_ERROR;
554 
555                 // populate the parseError struct
556                 if(srcIsLDH==FALSE){
557                     // failPos is always set the index of failure
558                     uprv_syntaxError(src,failPos, srcLength,parseError);
559                 }else if(src[0] == HYPHEN){
560                     // fail position is 0
561                     uprv_syntaxError(src,0,srcLength,parseError);
562                 }else{
563                     // the last index in the source is always length-1
564                     uprv_syntaxError(src, (srcLength>0) ? srcLength-1 : srcLength, srcLength,parseError);
565                 }
566 
567                 goto CLEANUP;
568             }
569         }*/
570         // just return the source
571         //copy the source to destination
572         if(srcLength <= destCapacity){
573             uprv_memmove(dest,src,srcLength * U_SIZEOF_UCHAR);
574         }
575         reqLength = srcLength;
576     }
577 
578 
579 CLEANUP:
580 
581     if(b1 != b1Stack && b1!=src){
582         uprv_free(b1);
583     }
584     if(b2 != b2Stack){
585         uprv_free(b2);
586     }
587     uprv_free(caseFlags);
588 
589     // The RFC states that
590     // <quote>
591     // ToUnicode never fails. If any step fails, then the original input
592     // is returned immediately in that step.
593     // </quote>
594     // So if any step fails lets copy source to destination
595     if(U_FAILURE(*status)){
596         //copy the source to destination
597         if(dest && srcLength <= destCapacity){
598             // srcLength should have already been set earlier.
599             U_ASSERT(srcLength >= 0);
600             uprv_memmove(dest,src,srcLength * U_SIZEOF_UCHAR);
601         }
602         reqLength = srcLength;
603         *status = U_ZERO_ERROR;
604     }
605 
606     return u_terminateUChars(dest, destCapacity, reqLength, status);
607 }
608 
609 U_CAPI int32_t U_EXPORT2
uidna_toASCII(const UChar * src,int32_t srcLength,UChar * dest,int32_t destCapacity,int32_t options,UParseError * parseError,UErrorCode * status)610 uidna_toASCII(const UChar* src, int32_t srcLength,
611               UChar* dest, int32_t destCapacity,
612               int32_t options,
613               UParseError* parseError,
614               UErrorCode* status){
615 
616     if(status == NULL || U_FAILURE(*status)){
617         return 0;
618     }
619     if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
620         *status = U_ILLEGAL_ARGUMENT_ERROR;
621         return 0;
622     }
623 
624     UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
625 
626     if(U_FAILURE(*status)){
627         return -1;
628     }
629 
630     int32_t retLen = _internal_toASCII(src, srcLength, dest, destCapacity, options, nameprep, parseError, status);
631 
632     /* close the profile*/
633     usprep_close(nameprep);
634 
635     return retLen;
636 }
637 
638 U_CAPI int32_t U_EXPORT2
uidna_toUnicode(const UChar * src,int32_t srcLength,UChar * dest,int32_t destCapacity,int32_t options,UParseError * parseError,UErrorCode * status)639 uidna_toUnicode(const UChar* src, int32_t srcLength,
640                 UChar* dest, int32_t destCapacity,
641                 int32_t options,
642                 UParseError* parseError,
643                 UErrorCode* status){
644 
645     if(status == NULL || U_FAILURE(*status)){
646         return 0;
647     }
648     if( (src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
649         *status = U_ILLEGAL_ARGUMENT_ERROR;
650         return 0;
651     }
652 
653     UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
654 
655     if(U_FAILURE(*status)){
656         return -1;
657     }
658 
659     int32_t retLen = _internal_toUnicode(src, srcLength, dest, destCapacity, options, nameprep, parseError, status);
660 
661     usprep_close(nameprep);
662 
663     return retLen;
664 }
665 
666 
667 U_CAPI int32_t U_EXPORT2
uidna_IDNToASCII(const UChar * src,int32_t srcLength,UChar * dest,int32_t destCapacity,int32_t options,UParseError * parseError,UErrorCode * status)668 uidna_IDNToASCII(  const UChar *src, int32_t srcLength,
669                    UChar* dest, int32_t destCapacity,
670                    int32_t options,
671                    UParseError *parseError,
672                    UErrorCode *status){
673 
674     if(status == NULL || U_FAILURE(*status)){
675         return 0;
676     }
677     if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
678         *status = U_ILLEGAL_ARGUMENT_ERROR;
679         return 0;
680     }
681 
682     int32_t reqLength = 0;
683 
684     UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
685 
686     if(U_FAILURE(*status)){
687         return 0;
688     }
689 
690     //initialize pointers
691     UChar *delimiter = (UChar*)src;
692     UChar *labelStart = (UChar*)src;
693     UChar *currentDest = (UChar*) dest;
694     int32_t remainingLen = srcLength;
695     int32_t remainingDestCapacity = destCapacity;
696     int32_t labelLen = 0, labelReqLength = 0;
697     UBool done = FALSE;
698 
699 
700     for(;;){
701 
702         labelLen = getNextSeparator(labelStart,remainingLen, &delimiter,&done);
703         labelReqLength = 0;
704         if(!(labelLen==0 && done)){// make sure this is not a root label separator.
705 
706             labelReqLength = _internal_toASCII( labelStart, labelLen,
707                                                 currentDest, remainingDestCapacity,
708                                                 options, nameprep,
709                                                 parseError, status);
710 
711             if(*status == U_BUFFER_OVERFLOW_ERROR){
712 
713                 *status = U_ZERO_ERROR; // reset error
714                 remainingDestCapacity = 0;
715             }
716         }
717 
718 
719         if(U_FAILURE(*status)){
720             break;
721         }
722 
723         reqLength +=labelReqLength;
724         // adjust the destination pointer
725         if(labelReqLength < remainingDestCapacity){
726             currentDest = currentDest + labelReqLength;
727             remainingDestCapacity -= labelReqLength;
728         }else{
729             // should never occur
730             remainingDestCapacity = 0;
731         }
732 
733         if(done == TRUE){
734             break;
735         }
736 
737         // add the label separator
738         if(remainingDestCapacity > 0){
739             *currentDest++ = FULL_STOP;
740             remainingDestCapacity--;
741         }
742         reqLength++;
743 
744         labelStart = delimiter;
745         if(remainingLen >0 ){
746             remainingLen = (int32_t)(srcLength - (delimiter - src));
747         }
748 
749     }
750 
751     if(reqLength > MAX_DOMAIN_NAME_LENGTH){
752         *status = U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR;
753     }
754 
755     usprep_close(nameprep);
756 
757     return u_terminateUChars(dest, destCapacity, reqLength, status);
758 }
759 
760 U_CAPI int32_t U_EXPORT2
uidna_IDNToUnicode(const UChar * src,int32_t srcLength,UChar * dest,int32_t destCapacity,int32_t options,UParseError * parseError,UErrorCode * status)761 uidna_IDNToUnicode(  const UChar* src, int32_t srcLength,
762                      UChar* dest, int32_t destCapacity,
763                      int32_t options,
764                      UParseError* parseError,
765                      UErrorCode* status){
766 
767     if(status == NULL || U_FAILURE(*status)){
768         return 0;
769     }
770     if((src==NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
771         *status = U_ILLEGAL_ARGUMENT_ERROR;
772         return 0;
773     }
774 
775     int32_t reqLength = 0;
776 
777     UStringPrepProfile* nameprep = usprep_openByType(USPREP_RFC3491_NAMEPREP, status);
778 
779     if(U_FAILURE(*status)){
780         return 0;
781     }
782 
783     //initialize pointers
784     UChar *delimiter = (UChar*)src;
785     UChar *labelStart = (UChar*)src;
786     UChar *currentDest = (UChar*) dest;
787     int32_t remainingLen = srcLength;
788     int32_t remainingDestCapacity = destCapacity;
789     int32_t labelLen = 0, labelReqLength = 0;
790     UBool done = FALSE;
791 
792     for(;;){
793 
794         labelLen = getNextSeparator(labelStart,remainingLen, &delimiter,&done);
795 
796         // The RFC states that
797         // <quote>
798         // ToUnicode never fails. If any step fails, then the original input
799         // is returned immediately in that step.
800         // </quote>
801         // _internal_toUnicode will copy the label.
802         /*if(labelLen==0 && done==FALSE){
803             *status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
804             break;
805         }*/
806 
807         labelReqLength = _internal_toUnicode(labelStart, labelLen,
808                                              currentDest, remainingDestCapacity,
809                                              options, nameprep,
810                                              parseError, status);
811 
812         if(*status == U_BUFFER_OVERFLOW_ERROR){
813             *status = U_ZERO_ERROR; // reset error
814             remainingDestCapacity = 0;
815         }
816 
817         if(U_FAILURE(*status)){
818             break;
819         }
820 
821         reqLength +=labelReqLength;
822         // adjust the destination pointer
823         if(labelReqLength < remainingDestCapacity){
824             currentDest = currentDest + labelReqLength;
825             remainingDestCapacity -= labelReqLength;
826         }else{
827             // should never occur
828             remainingDestCapacity = 0;
829         }
830 
831         if(done == TRUE){
832             break;
833         }
834 
835         // add the label separator
836         // Unlike the ToASCII operation we don't normalize the label separators
837         if(remainingDestCapacity > 0){
838             *currentDest++ = *(labelStart + labelLen);
839             remainingDestCapacity--;
840         }
841         reqLength++;
842 
843         labelStart = delimiter;
844         if(remainingLen >0 ){
845             remainingLen = (int32_t)(srcLength - (delimiter - src));
846         }
847 
848     }
849 
850     if(reqLength > MAX_DOMAIN_NAME_LENGTH){
851         *status = U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR;
852     }
853 
854     usprep_close(nameprep);
855 
856     return u_terminateUChars(dest, destCapacity, reqLength, status);
857 }
858 
859 U_CAPI int32_t U_EXPORT2
uidna_compare(const UChar * s1,int32_t length1,const UChar * s2,int32_t length2,int32_t options,UErrorCode * status)860 uidna_compare(  const UChar *s1, int32_t length1,
861                 const UChar *s2, int32_t length2,
862                 int32_t options,
863                 UErrorCode* status){
864 
865     if(status == NULL || U_FAILURE(*status)){
866         return -1;
867     }
868 
869     UChar b1Stack[MAX_IDN_BUFFER_SIZE], b2Stack[MAX_IDN_BUFFER_SIZE];
870     UChar *b1 = b1Stack, *b2 = b2Stack;
871     int32_t b1Len, b2Len, b1Capacity = MAX_IDN_BUFFER_SIZE, b2Capacity = MAX_IDN_BUFFER_SIZE;
872     int32_t result=-1;
873 
874     UParseError parseError;
875 
876     b1Len = uidna_IDNToASCII(s1, length1, b1, b1Capacity, options, &parseError, status);
877     if(*status == U_BUFFER_OVERFLOW_ERROR){
878         // redo processing of string
879         b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
880         if(b1==NULL){
881             *status = U_MEMORY_ALLOCATION_ERROR;
882             goto CLEANUP;
883         }
884 
885         *status = U_ZERO_ERROR; // reset error
886 
887         b1Len = uidna_IDNToASCII(s1,length1,b1,b1Len, options, &parseError, status);
888 
889     }
890 
891     b2Len = uidna_IDNToASCII(s2,length2, b2,b2Capacity, options, &parseError, status);
892     if(*status == U_BUFFER_OVERFLOW_ERROR){
893         // redo processing of string
894         b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
895         if(b2==NULL){
896             *status = U_MEMORY_ALLOCATION_ERROR;
897             goto CLEANUP;
898         }
899 
900         *status = U_ZERO_ERROR; // reset error
901 
902         b2Len = uidna_IDNToASCII(s2, length2, b2, b2Len, options, &parseError, status);
903 
904     }
905     // when toASCII is applied all label separators are replaced with FULL_STOP
906     result = compareCaseInsensitiveASCII(b1,b1Len,b2,b2Len);
907 
908 CLEANUP:
909     if(b1 != b1Stack){
910         uprv_free(b1);
911     }
912 
913     if(b2 != b2Stack){
914         uprv_free(b2);
915     }
916 
917     return result;
918 }
919 
920 #endif /* #if !UCONFIG_NO_IDNA */
921