]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/text/IDNA.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / text / IDNA.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2003-2009, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 \r
8 package com.ibm.icu.text;\r
9 \r
10 import com.ibm.icu.impl.Punycode;\r
11 \r
12 /**\r
13  *\r
14  * IDNA API implements the IDNA protocol as defined in the <a href="http://www.ietf.org/rfc/rfc3490.txt">IDNA RFC</a>.\r
15  * The draft defines 2 operations: ToASCII and ToUnicode. Domain labels \r
16  * containing non-ASCII code points are required to be processed by\r
17  * ToASCII operation before passing it to resolver libraries. Domain names\r
18  * that are obtained from resolver libraries are required to be processed by\r
19  * ToUnicode operation before displaying the domain name to the user.\r
20  * IDNA requires that implementations process input strings with \r
21  * <a href="http://www.ietf.org/rfc/rfc3491.txt">Nameprep</a>, \r
22  * which is a profile of <a href="http://www.ietf.org/rfc/rfc3454.txt">Stringprep</a> , \r
23  * and then with <a href="http://www.ietf.org/rfc/rfc3492.txt">Punycode</a>. \r
24  * Implementations of IDNA MUST fully implement Nameprep and Punycode; \r
25  * neither Nameprep nor Punycode are optional.\r
26  * The input and output of ToASCII and ToUnicode operations are Unicode \r
27  * and are designed to be chainable, i.e., applying ToASCII or ToUnicode operations\r
28  * multiple times to an input string will yield the same result as applying the operation\r
29  * once.\r
30  * ToUnicode(ToUnicode(ToUnicode...(ToUnicode(string)))) == ToUnicode(string) \r
31  * ToASCII(ToASCII(ToASCII...(ToASCII(string))) == ToASCII(string).\r
32  * \r
33  * @author Ram Viswanadha\r
34  * @stable ICU 2.8\r
35  */\r
36 public final class IDNA {\r
37 \r
38     /* IDNA ACE Prefix is "xn--" */\r
39     private static char[] ACE_PREFIX                = new char[]{ 0x0078,0x006E,0x002d,0x002d } ;\r
40     //private static final int ACE_PREFIX_LENGTH      = ACE_PREFIX.length;\r
41 \r
42     private static final int MAX_LABEL_LENGTH       = 63;\r
43     private static final int HYPHEN                 = 0x002D;\r
44     private static final int CAPITAL_A              = 0x0041;\r
45     private static final int CAPITAL_Z              = 0x005A;\r
46     private static final int LOWER_CASE_DELTA       = 0x0020;\r
47     private static final int FULL_STOP              = 0x002E;\r
48     private static final int MAX_DOMAIN_NAME_LENGTH = 255;\r
49     /** \r
50      * Option to prohibit processing of unassigned codepoints in the input and\r
51      * do not check if the input conforms to STD-3 ASCII rules.\r
52      * \r
53      * @see  #convertToASCII #convertToUnicode\r
54      * @stable ICU 2.8\r
55      */\r
56     public static final int DEFAULT             = 0x0000;\r
57     /** \r
58      * Option to allow processing of unassigned codepoints in the input\r
59      * \r
60      * @see  #convertToASCII #convertToUnicode\r
61      * @stable ICU 2.8\r
62      */\r
63     public static final int ALLOW_UNASSIGNED    = 0x0001;\r
64     /** \r
65      * Option to check if input conforms to STD-3 ASCII rules\r
66      * \r
67      * @see #convertToASCII #convertToUnicode\r
68      * @stable ICU 2.8\r
69      */\r
70     public static final int USE_STD3_RULES      = 0x0002;\r
71     \r
72     // static final singleton object that is initialized\r
73     // at class initialization time, hence guaranteed to\r
74     // be initialized and thread safe\r
75     private static final IDNA singleton  = new IDNA();\r
76     \r
77     // The NamePrep profile object\r
78     private StringPrep namePrep;\r
79     \r
80     /* private constructor to prevent construction of the object */\r
81     private IDNA(){\r
82         namePrep = StringPrep.getInstance(StringPrep.RFC3491_NAMEPREP);\r
83     }\r
84     \r
85     private static boolean startsWithPrefix(StringBuffer src){\r
86         boolean startsWithPrefix = true;\r
87 \r
88         if(src.length() < ACE_PREFIX.length){\r
89             return false;\r
90         }\r
91         for(int i=0; i<ACE_PREFIX.length;i++){\r
92             if(toASCIILower(src.charAt(i)) != ACE_PREFIX[i]){\r
93                 startsWithPrefix = false;\r
94             }\r
95         }\r
96         return startsWithPrefix;\r
97     }\r
98 \r
99     private static char toASCIILower(char ch){\r
100         if(CAPITAL_A <= ch && ch <= CAPITAL_Z){\r
101             return (char)(ch + LOWER_CASE_DELTA);\r
102         }\r
103         return ch;\r
104     }\r
105 \r
106     private static StringBuffer toASCIILower(StringBuffer src){\r
107         StringBuffer dest = new StringBuffer();\r
108         for(int i=0; i<src.length();i++){\r
109             dest.append(toASCIILower(src.charAt(i)));\r
110         }\r
111         return dest;\r
112     }\r
113 \r
114     private static int compareCaseInsensitiveASCII(StringBuffer s1, StringBuffer s2){\r
115         char c1,c2;\r
116         int rc;\r
117         for(int i =0;/* no condition */;i++) {\r
118             /* If we reach the ends of both strings then they match */\r
119             if(i == s1.length()) {\r
120                 return 0;\r
121             }\r
122 \r
123             c1 = s1.charAt(i);\r
124             c2 = s2.charAt(i);\r
125         \r
126             /* Case-insensitive comparison */\r
127             if(c1!=c2) {\r
128                 rc=toASCIILower(c1)-toASCIILower(c2);\r
129                 if(rc!=0) {\r
130                     return rc;\r
131                 }\r
132             }\r
133         }\r
134     }\r
135    \r
136     private static int getSeparatorIndex(char[] src,int start, int limit){\r
137         for(; start<limit;start++){\r
138             if(isLabelSeparator(src[start])){\r
139                 return start;\r
140             }\r
141         }\r
142         // we have not found the separator just return length\r
143         return start;\r
144     }\r
145     \r
146     /*\r
147     private static int getSeparatorIndex(UCharacterIterator iter){\r
148         int currentIndex = iter.getIndex();\r
149         int separatorIndex = 0;\r
150         int ch;\r
151         while((ch=iter.next())!= UCharacterIterator.DONE){\r
152             if(isLabelSeparator(ch)){\r
153                 separatorIndex = iter.getIndex();\r
154                 iter.setIndex(currentIndex);\r
155                 return separatorIndex;\r
156             }\r
157         }\r
158         // reset index\r
159         iter.setIndex(currentIndex);\r
160         // we have not found the separator just return the length\r
161        \r
162     }\r
163     */\r
164     \r
165 \r
166     private static boolean isLDHChar(int ch){\r
167         // high runner case\r
168         if(ch>0x007A){\r
169             return false;\r
170         }\r
171         //[\\u002D \\u0030-\\u0039 \\u0041-\\u005A \\u0061-\\u007A]\r
172         if( (ch==0x002D) || \r
173             (0x0030 <= ch && ch <= 0x0039) ||\r
174             (0x0041 <= ch && ch <= 0x005A) ||\r
175             (0x0061 <= ch && ch <= 0x007A)\r
176           ){\r
177             return true;\r
178         }\r
179         return false;\r
180     }\r
181     \r
182     /**\r
183      * Ascertain if the given code point is a label separator as \r
184      * defined by the IDNA RFC\r
185      * \r
186      * @param ch The code point to be ascertained\r
187      * @return true if the char is a label separator\r
188      * @stable ICU 2.8\r
189      */\r
190     private static boolean isLabelSeparator(int ch){\r
191         switch(ch){\r
192             case 0x002e:\r
193             case 0x3002:\r
194             case 0xFF0E:\r
195             case 0xFF61:\r
196                 return true;\r
197             default:\r
198                 return false;           \r
199         }\r
200     }\r
201        \r
202     /**\r
203      * This function implements the ToASCII operation as defined in the IDNA RFC.\r
204      * This operation is done on <b>single labels</b> before sending it to something that expects\r
205      * ASCII names. A label is an individual part of a domain name. Labels are usually\r
206      * separated by dots; e.g." "www.example.com" is composed of 3 labels \r
207      * "www","example", and "com".\r
208      *\r
209      * @param src       The input string to be processed\r
210      * @param options   A bit set of options:\r
211      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
212      *                              and do not use STD3 ASCII rules\r
213      *                              If unassigned code points are found the operation fails with \r
214      *                              StringPrepParseException.\r
215      *\r
216      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
217      *                              If this option is set, the unassigned code points are in the input \r
218      *                              are treated as normal Unicode code points.\r
219      *                          \r
220      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
221      *                              If this option is set and the input does not satisfy STD3 rules,  \r
222      *                              the operation will fail with ParseException\r
223      * @return StringBuffer the converted String\r
224      * @throws StringPrepParseException When an error occurs for parsing a string.\r
225      * @stable ICU 2.8\r
226      */    \r
227     public static StringBuffer convertToASCII(String src, int options)\r
228         throws StringPrepParseException{\r
229         UCharacterIterator iter = UCharacterIterator.getInstance(src);\r
230         return convertToASCII(iter,options);\r
231     }\r
232     \r
233     /**\r
234      * This function implements the ToASCII operation as defined in the IDNA RFC.\r
235      * This operation is done on <b>single labels</b> before sending it to something that expects\r
236      * ASCII names. A label is an individual part of a domain name. Labels are usually\r
237      * separated by dots; e.g." "www.example.com" is composed of 3 labels \r
238      * "www","example", and "com".\r
239      *\r
240      * @param src       The input string as StringBuffer to be processed\r
241      * @param options   A bit set of options:\r
242      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
243      *                              and do not use STD3 ASCII rules\r
244      *                              If unassigned code points are found the operation fails with \r
245      *                              ParseException.\r
246      *\r
247      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
248      *                              If this option is set, the unassigned code points are in the input \r
249      *                              are treated as normal Unicode code points.\r
250      *                          \r
251      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
252      *                              If this option is set and the input does not satisfy STD3 rules,  \r
253      *                              the operation will fail with ParseException\r
254      * @return StringBuffer the converted String\r
255      * @stable ICU 2.8\r
256      */\r
257     public static StringBuffer convertToASCII(StringBuffer src, int options)\r
258         throws StringPrepParseException{\r
259         UCharacterIterator iter = UCharacterIterator.getInstance(src);\r
260         return convertToASCII(iter,options);\r
261     }\r
262     \r
263     /**\r
264      * This function implements the ToASCII operation as defined in the IDNA RFC.\r
265      * This operation is done on <b>single labels</b> before sending it to something that expects\r
266      * ASCII names. A label is an individual part of a domain name. Labels are usually\r
267      * separated by dots; e.g." "www.example.com" is composed of 3 labels \r
268      * "www","example", and "com".\r
269      *\r
270      * @param src       The input string as UCharacterIterator to be processed\r
271      * @param options   A bit set of options:\r
272      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
273      *                              and do not use STD3 ASCII rules\r
274      *                              If unassigned code points are found the operation fails with \r
275      *                              ParseException.\r
276      *\r
277      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
278      *                              If this option is set, the unassigned code points are in the input \r
279      *                              are treated as normal Unicode code points.\r
280      *                          \r
281      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
282      *                              If this option is set and the input does not satisfy STD3 rules,  \r
283      *                              the operation will fail with ParseException\r
284      * @return StringBuffer the converted String\r
285      * @stable ICU 2.8\r
286      */\r
287     public static StringBuffer convertToASCII(UCharacterIterator src, int options)\r
288                 throws StringPrepParseException{\r
289         \r
290         boolean[] caseFlags = null;\r
291     \r
292         // the source contains all ascii codepoints\r
293         boolean srcIsASCII  = true;\r
294         // assume the source contains all LDH codepoints\r
295         boolean srcIsLDH = true; \r
296 \r
297         //get the options\r
298         boolean useSTD3ASCIIRules = ((options & USE_STD3_RULES) != 0);\r
299         int ch;\r
300         // step 1\r
301         while((ch = src.next())!= UCharacterIterator.DONE){\r
302             if(ch> 0x7f){\r
303                 srcIsASCII = false;\r
304             }\r
305         }\r
306         int failPos = -1;\r
307         src.setToStart();\r
308         StringBuffer processOut = null;\r
309         // step 2 is performed only if the source contains non ASCII\r
310         if(!srcIsASCII){\r
311             // step 2\r
312             processOut = singleton.namePrep.prepare(src, options);\r
313         }else{\r
314             processOut = new StringBuffer(src.getText());\r
315         }\r
316         int poLen = processOut.length();\r
317         \r
318         if(poLen==0){\r
319             throw new StringPrepParseException("Found zero length lable after NamePrep.",StringPrepParseException.ZERO_LENGTH_LABEL);\r
320         }\r
321         StringBuffer dest = new StringBuffer();\r
322         \r
323         // reset the variable to verify if output of prepare is ASCII or not\r
324         srcIsASCII = true;\r
325         \r
326         // step 3 & 4\r
327         for(int j=0;j<poLen;j++ ){\r
328             ch=processOut.charAt(j);\r
329             if(ch > 0x7F){\r
330                 srcIsASCII = false;\r
331             }else if(isLDHChar(ch)==false){\r
332                 // here we do not assemble surrogates\r
333                 // since we know that LDH code points\r
334                 // are in the ASCII range only\r
335                 srcIsLDH = false;\r
336                 failPos = j;\r
337             }\r
338         }\r
339     \r
340         if(useSTD3ASCIIRules == true){\r
341             // verify 3a and 3b\r
342             if( srcIsLDH == false /* source contains some non-LDH characters */\r
343                 || processOut.charAt(0) ==  HYPHEN \r
344                 || processOut.charAt(processOut.length()-1) == HYPHEN){\r
345 \r
346                 /* populate the parseError struct */\r
347                 if(srcIsLDH==false){\r
348                      throw new StringPrepParseException( "The input does not conform to the STD 3 ASCII rules",\r
349                                               StringPrepParseException.STD3_ASCII_RULES_ERROR,\r
350                                               processOut.toString(),\r
351                                              (failPos>0) ? (failPos-1) : failPos);\r
352                 }else if(processOut.charAt(0) == HYPHEN){\r
353                     throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules",\r
354                                               StringPrepParseException.STD3_ASCII_RULES_ERROR,processOut.toString(),0);\r
355      \r
356                 }else{\r
357                      throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules",\r
358                                               StringPrepParseException.STD3_ASCII_RULES_ERROR,\r
359                                               processOut.toString(),\r
360                                               (poLen>0) ? poLen-1 : poLen);\r
361 \r
362                 }\r
363             }\r
364         }\r
365         if(srcIsASCII){\r
366             dest =  processOut;\r
367         }else{\r
368             // step 5 : verify the sequence does not begin with ACE prefix\r
369             if(!startsWithPrefix(processOut)){\r
370 \r
371                 //step 6: encode the sequence with punycode\r
372                 caseFlags = new boolean[poLen];\r
373 \r
374                 StringBuffer punyout = Punycode.encode(processOut,caseFlags);\r
375 \r
376                 // convert all codepoints to lower case ASCII\r
377                 StringBuffer lowerOut = toASCIILower(punyout);\r
378 \r
379                 //Step 7: prepend the ACE prefix\r
380                 dest.append(ACE_PREFIX,0,ACE_PREFIX.length);\r
381                 //Step 6: copy the contents in b2 into dest\r
382                 dest.append(lowerOut);\r
383             }else{\r
384 \r
385                 throw new StringPrepParseException("The input does not start with the ACE Prefix.",\r
386                                          StringPrepParseException.ACE_PREFIX_ERROR,processOut.toString(),0);\r
387             }\r
388         }\r
389         if(dest.length() > MAX_LABEL_LENGTH){\r
390             throw new StringPrepParseException("The labels in the input are too long. Length > 63.", \r
391                                      StringPrepParseException.LABEL_TOO_LONG_ERROR,dest.toString(),0);\r
392         }\r
393         return dest;\r
394     }\r
395         \r
396     /**\r
397      * Convenience function that implements the IDNToASCII operation as defined in the IDNA RFC.\r
398      * This operation is done on complete domain names, e.g: "www.example.com". \r
399      * It is important to note that this operation can fail. If it fails, then the input \r
400      * domain name cannot be used as an Internationalized Domain Name and the application\r
401      * should have methods defined to deal with the failure.\r
402      * \r
403      * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name\r
404      * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, \r
405      * and then convert. This function does not offer that level of granularity. The options once  \r
406      * set will apply to all labels in the domain name\r
407      *\r
408      * @param src       The input string as UCharacterIterator to be processed\r
409      * @param options   A bit set of options:\r
410      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
411      *                              and do not use STD3 ASCII rules\r
412      *                              If unassigned code points are found the operation fails with \r
413      *                              ParseException.\r
414      *\r
415      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
416      *                              If this option is set, the unassigned code points are in the input \r
417      *                              are treated as normal Unicode code points.\r
418      *                          \r
419      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
420      *                              If this option is set and the input does not satisfy STD3 rules,  \r
421      *                              the operation will fail with ParseException\r
422      * @return StringBuffer the converted String\r
423      * @stable ICU 2.8\r
424      */\r
425     public static StringBuffer convertIDNToASCII(UCharacterIterator src, int options)\r
426             throws StringPrepParseException{\r
427         return convertIDNToASCII(src.getText(), options);          \r
428     }\r
429     \r
430     /**\r
431      * Convenience function that implements the IDNToASCII operation as defined in the IDNA RFC.\r
432      * This operation is done on complete domain names, e.g: "www.example.com". \r
433      * It is important to note that this operation can fail. If it fails, then the input \r
434      * domain name cannot be used as an Internationalized Domain Name and the application\r
435      * should have methods defined to deal with the failure.\r
436      * \r
437      * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name\r
438      * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, \r
439      * and then convert. This function does not offer that level of granularity. The options once  \r
440      * set will apply to all labels in the domain name\r
441      *\r
442      * @param src       The input string as a StringBuffer to be processed\r
443      * @param options   A bit set of options:\r
444      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
445      *                              and do not use STD3 ASCII rules\r
446      *                              If unassigned code points are found the operation fails with \r
447      *                              ParseException.\r
448      *\r
449      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
450      *                              If this option is set, the unassigned code points are in the input \r
451      *                              are treated as normal Unicode code points.\r
452      *                          \r
453      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
454      *                              If this option is set and the input does not satisfy STD3 rules,  \r
455      *                              the operation will fail with ParseException\r
456      * @return StringBuffer the converted String\r
457      * @stable ICU 2.8\r
458      */\r
459     public static StringBuffer convertIDNToASCII(StringBuffer src, int options)\r
460             throws StringPrepParseException{\r
461             return convertIDNToASCII(src.toString(), options);          \r
462     }\r
463     \r
464     /**\r
465      * Convenience function that implements the IDNToASCII operation as defined in the IDNA RFC.\r
466      * This operation is done on complete domain names, e.g: "www.example.com". \r
467      * It is important to note that this operation can fail. If it fails, then the input \r
468      * domain name cannot be used as an Internationalized Domain Name and the application\r
469      * should have methods defined to deal with the failure.\r
470      * \r
471      * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name\r
472      * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, \r
473      * and then convert. This function does not offer that level of granularity. The options once  \r
474      * set will apply to all labels in the domain name\r
475      *\r
476      * @param src       The input string to be processed\r
477      * @param options   A bit set of options:\r
478      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
479      *                              and do not use STD3 ASCII rules\r
480      *                              If unassigned code points are found the operation fails with \r
481      *                              ParseException.\r
482      *\r
483      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
484      *                              If this option is set, the unassigned code points are in the input \r
485      *                              are treated as normal Unicode code points.\r
486      *                          \r
487      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
488      *                              If this option is set and the input does not satisfy STD3 rules,  \r
489      *                              the operation will fail with ParseException\r
490      * @return StringBuffer the converted String\r
491      * @stable ICU 2.8\r
492      */\r
493     public static StringBuffer convertIDNToASCII(String src,int options)\r
494             throws StringPrepParseException{\r
495 \r
496         char[] srcArr = src.toCharArray();\r
497         StringBuffer result = new StringBuffer();\r
498         int sepIndex=0;\r
499         int oldSepIndex=0;\r
500         for(;;){\r
501             sepIndex = getSeparatorIndex(srcArr,sepIndex,srcArr.length);\r
502             String label = new String(srcArr,oldSepIndex,sepIndex-oldSepIndex);\r
503             //make sure this is not a root label separator.\r
504             if(!(label.length()==0 && sepIndex==srcArr.length)){\r
505                 UCharacterIterator iter = UCharacterIterator.getInstance(label);\r
506                 result.append(convertToASCII(iter,options));\r
507             }\r
508             if(sepIndex==srcArr.length){\r
509                 break;\r
510             }\r
511             \r
512             // increment the sepIndex to skip past the separator\r
513             sepIndex++;\r
514             oldSepIndex = sepIndex;\r
515             result.append((char)FULL_STOP);\r
516         }\r
517         if(result.length() > MAX_DOMAIN_NAME_LENGTH){\r
518             throw new StringPrepParseException("The output exceed the max allowed length.", StringPrepParseException.DOMAIN_NAME_TOO_LONG_ERROR);\r
519         }\r
520         return result;\r
521     }\r
522 \r
523     \r
524     /**\r
525      * This function implements the ToUnicode operation as defined in the IDNA RFC.\r
526      * This operation is done on <b>single labels</b> before sending it to something that expects\r
527      * Unicode names. A label is an individual part of a domain name. Labels are usually\r
528      * separated by dots; for e.g." "www.example.com" is composed of 3 labels \r
529      * "www","example", and "com".\r
530      * \r
531      * @param src       The input string to be processed\r
532      * @param options   A bit set of options:\r
533      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
534      *                              and do not use STD3 ASCII rules\r
535      *                              If unassigned code points are found the operation fails with \r
536      *                              ParseException.\r
537      *\r
538      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
539      *                              If this option is set, the unassigned code points are in the input \r
540      *                              are treated as normal Unicode code points.\r
541      *                          \r
542      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
543      *                              If this option is set and the input does not satisfy STD3 rules,  \r
544      *                              the operation will fail with ParseException\r
545      * @return StringBuffer the converted String\r
546      * @stable ICU 2.8\r
547      */\r
548     public static StringBuffer convertToUnicode(String src, int options)\r
549            throws StringPrepParseException{\r
550         UCharacterIterator iter = UCharacterIterator.getInstance(src);\r
551         return convertToUnicode(iter,options);\r
552     }\r
553     \r
554     /**\r
555      * This function implements the ToUnicode operation as defined in the IDNA RFC.\r
556      * This operation is done on <b>single labels</b> before sending it to something that expects\r
557      * Unicode names. A label is an individual part of a domain name. Labels are usually\r
558      * separated by dots; for e.g." "www.example.com" is composed of 3 labels \r
559      * "www","example", and "com".\r
560      * \r
561      * @param src       The input string as StringBuffer to be processed\r
562      * @param options   A bit set of options:\r
563      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
564      *                              and do not use STD3 ASCII rules\r
565      *                              If unassigned code points are found the operation fails with \r
566      *                              ParseException.\r
567      *\r
568      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
569      *                              If this option is set, the unassigned code points are in the input \r
570      *                              are treated as normal Unicode code points.\r
571      *                          \r
572      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
573      *                              If this option is set and the input does not satisfy STD3 rules,  \r
574      *                              the operation will fail with ParseException\r
575      * @return StringBuffer the converted String\r
576      * @stable ICU 2.8\r
577      */\r
578     public static StringBuffer convertToUnicode(StringBuffer src, int options)\r
579            throws StringPrepParseException{\r
580         UCharacterIterator iter = UCharacterIterator.getInstance(src);\r
581         return convertToUnicode(iter,options);\r
582     }\r
583        \r
584     /**\r
585      * Function that implements the ToUnicode operation as defined in the IDNA RFC.\r
586      * This operation is done on <b>single labels</b> before sending it to something that expects\r
587      * Unicode names. A label is an individual part of a domain name. Labels are usually\r
588      * separated by dots; for e.g." "www.example.com" is composed of 3 labels \r
589      * "www","example", and "com".\r
590      * \r
591      * @param src       The input string as UCharacterIterator to be processed\r
592      * @param options   A bit set of options:\r
593      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
594      *                              and do not use STD3 ASCII rules\r
595      *                              If unassigned code points are found the operation fails with \r
596      *                              ParseException.\r
597      *\r
598      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
599      *                              If this option is set, the unassigned code points are in the input \r
600      *                              are treated as normal Unicode code points.\r
601      *                          \r
602      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
603      *                              If this option is set and the input does not satisfy STD3 rules,  \r
604      *                              the operation will fail with ParseException\r
605      * @return StringBuffer the converted String\r
606      * @stable ICU 2.8\r
607      */\r
608     public static StringBuffer convertToUnicode(UCharacterIterator src, int options)\r
609            throws StringPrepParseException{\r
610         \r
611         boolean[] caseFlags = null;\r
612                 \r
613         // the source contains all ascii codepoints\r
614         boolean srcIsASCII  = true;\r
615         // assume the source contains all LDH codepoints\r
616         //boolean srcIsLDH = true; \r
617         \r
618         //get the options\r
619         //boolean useSTD3ASCIIRules = ((options & USE_STD3_RULES) != 0);\r
620         \r
621         //int failPos = -1;\r
622         int ch;\r
623         int saveIndex = src.getIndex();\r
624         // step 1: find out if all the codepoints in src are ASCII  \r
625         while((ch=src.next())!= UCharacterIterator.DONE){\r
626             if(ch>0x7F){\r
627                 srcIsASCII = false;\r
628             }/*else if((srcIsLDH = isLDHChar(ch))==false){\r
629                 failPos = src.getIndex();\r
630             }*/\r
631         }\r
632         StringBuffer processOut;\r
633         \r
634         if(srcIsASCII == false){\r
635             try {\r
636                 // step 2: process the string\r
637                 src.setIndex(saveIndex);\r
638                 processOut = singleton.namePrep.prepare(src,options);\r
639             } catch (StringPrepParseException ex) {\r
640                 return new StringBuffer(src.getText());\r
641             }\r
642 \r
643         }else{\r
644             //just point to source\r
645             processOut = new StringBuffer(src.getText());\r
646         }\r
647         // TODO:\r
648         // The RFC states that \r
649         // <quote>\r
650         // ToUnicode never fails. If any step fails, then the original input\r
651         // is returned immediately in that step.\r
652         // </quote>\r
653         \r
654         //step 3: verify ACE Prefix\r
655         if(startsWithPrefix(processOut)){\r
656             StringBuffer decodeOut = null;\r
657 \r
658             //step 4: Remove the ACE Prefix\r
659             String temp = processOut.substring(ACE_PREFIX.length,processOut.length());\r
660 \r
661             //step 5: Decode using punycode\r
662             try {\r
663                 decodeOut = Punycode.decode(new StringBuffer(temp),caseFlags);\r
664             } catch (StringPrepParseException e) {\r
665                 decodeOut = null;\r
666             }\r
667         \r
668             //step 6:Apply toASCII\r
669             if (decodeOut != null) {\r
670                 StringBuffer toASCIIOut = convertToASCII(decodeOut, options);\r
671     \r
672                 //step 7: verify\r
673                 if(compareCaseInsensitiveASCII(processOut, toASCIIOut) !=0){\r
674 //                    throw new StringPrepParseException("The verification step prescribed by the RFC 3491 failed",\r
675 //                                             StringPrepParseException.VERIFICATION_ERROR); \r
676                     decodeOut = null;\r
677                 }\r
678             }\r
679 \r
680             //step 8: return output of step 5\r
681              if (decodeOut != null) {\r
682                  return decodeOut;\r
683              }\r
684         }\r
685             \r
686 //        }else{\r
687 //            // verify that STD3 ASCII rules are satisfied\r
688 //            if(useSTD3ASCIIRules == true){\r
689 //                if( srcIsLDH == false /* source contains some non-LDH characters */\r
690 //                    || processOut.charAt(0) ==  HYPHEN \r
691 //                    || processOut.charAt(processOut.length()-1) == HYPHEN){\r
692 //    \r
693 //                    if(srcIsLDH==false){\r
694 //                        throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules",\r
695 //                                                 StringPrepParseException.STD3_ASCII_RULES_ERROR,processOut.toString(),\r
696 //                                                 (failPos>0) ? (failPos-1) : failPos);\r
697 //                    }else if(processOut.charAt(0) == HYPHEN){\r
698 //                        throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules",\r
699 //                                                 StringPrepParseException.STD3_ASCII_RULES_ERROR,\r
700 //                                                 processOut.toString(),0);\r
701 //         \r
702 //                    }else{\r
703 //                        throw new StringPrepParseException("The input does not conform to the STD 3 ASCII rules",\r
704 //                                                 StringPrepParseException.STD3_ASCII_RULES_ERROR,\r
705 //                                                 processOut.toString(),\r
706 //                                                 processOut.length());\r
707 //    \r
708 //                    }\r
709 //                }\r
710 //            }\r
711 //            // just return the source\r
712 //            return new StringBuffer(src.getText());\r
713 //        }  \r
714         \r
715         return new StringBuffer(src.getText());\r
716     }\r
717     \r
718     /**\r
719      * Convenience function that implements the IDNToUnicode operation as defined in the IDNA RFC.\r
720      * This operation is done on complete domain names, e.g: "www.example.com". \r
721      *\r
722      * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name\r
723      * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, \r
724      * and then convert. This function does not offer that level of granularity. The options once  \r
725      * set will apply to all labels in the domain name\r
726      *\r
727      * @param src       The input string as UCharacterIterator to be processed\r
728      * @param options   A bit set of options:\r
729      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
730      *                              and do not use STD3 ASCII rules\r
731      *                              If unassigned code points are found the operation fails with \r
732      *                              ParseException.\r
733      *\r
734      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
735      *                              If this option is set, the unassigned code points are in the input \r
736      *                              are treated as normal Unicode code points.\r
737      *                          \r
738      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
739      *                              If this option is set and the input does not satisfy STD3 rules,  \r
740      *                              the operation will fail with ParseException\r
741      * @return StringBuffer the converted String\r
742      * @stable ICU 2.8\r
743      */\r
744     public static StringBuffer convertIDNToUnicode(UCharacterIterator src, int options)\r
745         throws StringPrepParseException{\r
746         return convertIDNToUnicode(src.getText(), options);\r
747     }\r
748     \r
749     /**\r
750      * Convenience function that implements the IDNToUnicode operation as defined in the IDNA RFC.\r
751      * This operation is done on complete domain names, e.g: "www.example.com". \r
752      *\r
753      * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name\r
754      * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, \r
755      * and then convert. This function does not offer that level of granularity. The options once  \r
756      * set will apply to all labels in the domain name\r
757      *\r
758      * @param src       The input string as StringBuffer to be processed\r
759      * @param options   A bit set of options:\r
760      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
761      *                              and do not use STD3 ASCII rules\r
762      *                              If unassigned code points are found the operation fails with \r
763      *                              ParseException.\r
764      *\r
765      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
766      *                              If this option is set, the unassigned code points are in the input \r
767      *                              are treated as normal Unicode code points.\r
768      *                          \r
769      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
770      *                              If this option is set and the input does not satisfy STD3 rules,  \r
771      *                              the operation will fail with ParseException\r
772      * @return StringBuffer the converted String\r
773      * @stable ICU 2.8\r
774      */\r
775     public static StringBuffer convertIDNToUnicode(StringBuffer src, int options)\r
776         throws StringPrepParseException{\r
777         return convertIDNToUnicode(src.toString(), options);\r
778     }\r
779     \r
780     /**\r
781      * Convenience function that implements the IDNToUnicode operation as defined in the IDNA RFC.\r
782      * This operation is done on complete domain names, e.g: "www.example.com". \r
783      *\r
784      * <b>Note:</b> IDNA RFC specifies that a conformant application should divide a domain name\r
785      * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each, \r
786      * and then convert. This function does not offer that level of granularity. The options once  \r
787      * set will apply to all labels in the domain name\r
788      *\r
789      * @param src       The input string to be processed\r
790      * @param options   A bit set of options:\r
791      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
792      *                              and do not use STD3 ASCII rules\r
793      *                              If unassigned code points are found the operation fails with \r
794      *                              ParseException.\r
795      *\r
796      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
797      *                              If this option is set, the unassigned code points are in the input \r
798      *                              are treated as normal Unicode code points.\r
799      *                          \r
800      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
801      *                              If this option is set and the input does not satisfy STD3 rules,  \r
802      *                              the operation will fail with ParseException\r
803      * @return StringBuffer the converted String\r
804      * @stable ICU 2.8\r
805      */\r
806     public static StringBuffer convertIDNToUnicode(String src, int options)\r
807         throws StringPrepParseException{\r
808             \r
809         char[] srcArr = src.toCharArray();\r
810         StringBuffer result = new StringBuffer();\r
811         int sepIndex=0;\r
812         int oldSepIndex=0;\r
813         for(;;){\r
814             sepIndex = getSeparatorIndex(srcArr,sepIndex,srcArr.length);\r
815             String label = new String(srcArr,oldSepIndex,sepIndex-oldSepIndex);\r
816             if(label.length()==0 && sepIndex!=srcArr.length ){\r
817                 throw new StringPrepParseException("Found zero length lable after NamePrep.",StringPrepParseException.ZERO_LENGTH_LABEL);\r
818             }\r
819             UCharacterIterator iter = UCharacterIterator.getInstance(label);\r
820             result.append(convertToUnicode(iter,options));\r
821             if(sepIndex==srcArr.length){\r
822                 break;\r
823             }\r
824             // Unlike the ToASCII operation we don't normalize the label separators\r
825             result.append(srcArr[sepIndex]);\r
826             // increment the sepIndex to skip past the separator\r
827             sepIndex++;\r
828             oldSepIndex =sepIndex;\r
829         }\r
830         if(result.length() > MAX_DOMAIN_NAME_LENGTH){\r
831             throw new StringPrepParseException("The output exceed the max allowed length.", StringPrepParseException.DOMAIN_NAME_TOO_LONG_ERROR);\r
832         }\r
833         return result;\r
834     }\r
835     \r
836     /**\r
837      * Compare two IDN strings for equivalence.\r
838      * This function splits the domain names into labels and compares them.\r
839      * According to IDN RFC, whenever two labels are compared, they are \r
840      * considered equal if and only if their ASCII forms (obtained by \r
841      * applying toASCII) match using an case-insensitive ASCII comparison.\r
842      * Two domain names are considered a match if and only if all labels \r
843      * match regardless of whether label separators match.\r
844      * \r
845      * @param s1        First IDN string as StringBuffer\r
846      * @param s2        Second IDN string as StringBuffer\r
847      * @param options   A bit set of options:\r
848      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
849      *                              and do not use STD3 ASCII rules\r
850      *                              If unassigned code points are found the operation fails with \r
851      *                              ParseException.\r
852      *\r
853      *  - IDNA.ALLOW_UNASSIGNED    Unassigned values can be converted to ASCII for query operations\r
854      *                              If this option is set, the unassigned code points are in the input \r
855      *                              are treated as normal Unicode code points.\r
856      *                          \r
857      *  - IDNA.USE_STD3_RULES      Use STD3 ASCII rules for host name syntax restrictions\r
858      *                              If this option is set and the input does not satisfy STD3 rules,  \r
859      *                              the operation will fail with ParseException\r
860      * @return 0 if the strings are equal, > 0 if s1 > s2 and < 0 if s1 < s2\r
861      * @stable ICU 2.8\r
862      */\r
863     //  TODO: optimize\r
864     public static int compare(StringBuffer s1, StringBuffer s2, int options)\r
865         throws StringPrepParseException{\r
866         if(s1==null || s2 == null){\r
867             throw new IllegalArgumentException("One of the source buffers is null");\r
868         }\r
869         StringBuffer s1Out = convertIDNToASCII(s1.toString(),options);\r
870         StringBuffer s2Out = convertIDNToASCII(s2.toString(), options);\r
871         return compareCaseInsensitiveASCII(s1Out,s2Out);\r
872     }\r
873     \r
874     /**\r
875      * Compare two IDN strings for equivalence.\r
876      * This function splits the domain names into labels and compares them.\r
877      * According to IDN RFC, whenever two labels are compared, they are \r
878      * considered equal if and only if their ASCII forms (obtained by \r
879      * applying toASCII) match using an case-insensitive ASCII comparison.\r
880      * Two domain names are considered a match if and only if all labels \r
881      * match regardless of whether label separators match.\r
882      * \r
883      * @param s1        First IDN string \r
884      * @param s2        Second IDN string\r
885      * @param options   A bit set of options:\r
886      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
887      *                              and do not use STD3 ASCII rules\r
888      *                              If unassigned code points are found the operation fails with \r
889      *                              ParseException.\r
890      *\r
891      *  - IDNA.ALLOW_UNASSIGNED    Unassigned values can be converted to ASCII for query operations\r
892      *                              If this option is set, the unassigned code points are in the input \r
893      *                              are treated as normal Unicode code points.\r
894      *                          \r
895      *  - IDNA.USE_STD3_RULES      Use STD3 ASCII rules for host name syntax restrictions\r
896      *                              If this option is set and the input does not satisfy STD3 rules,  \r
897      *                              the operation will fail with ParseException\r
898      * @return 0 if the strings are equal, > 0 if s1 > s2 and < 0 if s1 < s2\r
899      * @stable ICU 2.8\r
900      */\r
901     //  TODO: optimize\r
902     public static int compare(String s1, String s2, int options)\r
903         throws StringPrepParseException{\r
904         if(s1==null || s2 == null){\r
905             throw new IllegalArgumentException("One of the source buffers is null");\r
906         }\r
907         StringBuffer s1Out = convertIDNToASCII(s1, options);\r
908         StringBuffer s2Out = convertIDNToASCII(s2, options);\r
909         return compareCaseInsensitiveASCII(s1Out,s2Out);\r
910     }\r
911     /**\r
912      * Compare two IDN strings for equivalence.\r
913      * This function splits the domain names into labels and compares them.\r
914      * According to IDN RFC, whenever two labels are compared, they are \r
915      * considered equal if and only if their ASCII forms (obtained by \r
916      * applying toASCII) match using an case-insensitive ASCII comparison.\r
917      * Two domain names are considered a match if and only if all labels \r
918      * match regardless of whether label separators match.\r
919      * \r
920      * @param s1        First IDN string as UCharacterIterator\r
921      * @param s2        Second IDN string as UCharacterIterator\r
922      * @param options   A bit set of options:\r
923      *  - IDNA.DEFAULT              Use default options, i.e., do not process unassigned code points\r
924      *                              and do not use STD3 ASCII rules\r
925      *                              If unassigned code points are found the operation fails with \r
926      *                              ParseException.\r
927      *\r
928      *  - IDNA.ALLOW_UNASSIGNED     Unassigned values can be converted to ASCII for query operations\r
929      *                              If this option is set, the unassigned code points are in the input \r
930      *                              are treated as normal Unicode code points.\r
931      *                          \r
932      *  - IDNA.USE_STD3_RULES       Use STD3 ASCII rules for host name syntax restrictions\r
933      *                              If this option is set and the input does not satisfy STD3 rules,  \r
934      *                              the operation will fail with ParseException\r
935      * @return 0 if the strings are equal, > 0 if i1 > i2 and < 0 if i1 < i2\r
936      * @stable ICU 2.8\r
937      */\r
938     //  TODO: optimize\r
939     public static int compare(UCharacterIterator s1, UCharacterIterator s2, int options)\r
940         throws StringPrepParseException{\r
941         if(s1==null || s2 == null){\r
942             throw new IllegalArgumentException("One of the source buffers is null");\r
943         }\r
944         StringBuffer s1Out = convertIDNToASCII(s1.getText(), options);\r
945         StringBuffer s2Out = convertIDNToASCII(s2.getText(), options);\r
946         return compareCaseInsensitiveASCII(s1Out,s2Out);\r
947     }\r
948 }\r