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