]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/tests/core/src/com/ibm/icu/dev/test/stringprep/PunycodeReference.java
Added flags.
[Dictionary.git] / jars / icu4j-52_1 / main / tests / core / src / com / ibm / icu / dev / test / stringprep / PunycodeReference.java
1 /*
2  *******************************************************************************
3  * Copyright (C) 2003-2007, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6 */
7
8 /*
9  * 
10 Disclaimer and license
11
12     Regarding this entire document or any portion of it (including
13     the pseudocode and C code), the author makes no guarantees and
14     is not responsible for any damage resulting from its use.  The
15     author grants irrevocable permission to anyone to use, modify,
16     and distribute it in any way that does not diminish the rights
17     of anyone else to use, modify, and distribute it, provided that
18     redistributed derivative works do not contain misleading author or
19     version information.  Derivative works need not be licensed under
20     similar terms.
21
22 punycode.c 0.4.0 (2001-Nov-17-Sat)
23 http://www.cs.berkeley.edu/~amc/idn/
24 Adam M. Costello
25 http://www.nicemice.net/amc/
26 */
27
28 package com.ibm.icu.dev.test.stringprep;
29 import com.ibm.icu.text.StringPrepParseException;
30 import com.ibm.icu.text.UCharacterIterator;
31 import com.ibm.icu.text.UTF16;
32
33 /**
34  * The implementation is direct port of C code in the RFC
35  */
36
37 public final class PunycodeReference {
38     /*** punycode status codes */
39     public static final int punycode_success=0;
40     public static final int punycode_bad_input=1;   /* Input is invalid.                       */
41     public static final int punycode_big_output=2;  /* Output would exceed the space provided. */
42     public static final int punycode_overflow =3;    /* Input needs wider integers to process.  */
43     
44     /*** Bootstring parameters for Punycode ***/
45     private static final int base = 36;
46     private static final int tmin = 1;
47     private static final int tmax = 26;
48     private static final int skew = 38;
49     private static final int damp = 700;
50     private static final int initial_bias = 72;
51     private static final int initial_n = 0x80;
52     private static final int delimiter = 0x2D;
53     
54     
55 //    private static final long UNSIGNED_INT_MASK = 0xffffffffL;
56     
57     /* basic(cp) tests whether cp is a basic code point: */
58     private static boolean basic(int cp){
59         return (char)(cp) < 0x80;
60     }
61
62     /* delim(cp) tests whether cp is a delimiter: */
63     private static boolean delim(int cp){
64         return ((cp) == delimiter);
65     }
66
67     /* decode_digit(cp) returns the numeric value of a basic code */
68     /* point (for use in representing integers) in the range 0 to */
69     /* base-1, or base if cp is does not represent a value.       */
70
71     private static int decode_digit(int cp)
72     {
73       return  cp - 48 < 10 ? cp - 22 :  cp - 65 < 26 ? cp - 65 :
74               cp - 97 < 26 ? cp - 97 :  base;
75     }
76
77     /* encode_digit(d,flag) returns the basic code point whose value      */
78     /* (when used for representing integers) is d, which needs to be in   */
79     /* the range 0 to base-1.  The lowercase form is used unless flag is  */
80     /* nonzero, in which case the uppercase form is used.  The behavior   */
81     /* is undefined if flag is nonzero and digit d has no uppercase form. */
82
83     private static char encode_digit(int d, int flag)
84     {
85       return (char) (d + 22 + (75 * ((d < 26) ? 1 : 0) - (((flag != 0) ? 1 :0) << 5)));
86       /*  0..25 map to ASCII a..z or A..Z */
87       /* 26..35 map to ASCII 0..9         */
88     }
89
90     /* flagged(bcp) tests whether a basic code point is flagged */
91     /* (uppercase).  The behavior is undefined if bcp is not a  */
92     /* basic code point.                                        */
93
94     private static boolean flagged(int bcp){
95          return ((bcp) - 65 < 26);
96     }
97
98     /* encode_basic(bcp,flag) forces a basic code point to lowercase */
99     /* if flag is zero, uppercase if flag is nonzero, and returns    */
100     /* the resulting code point.  The code point is unchanged if it  */
101     /* is caseless.  The behavior is undefined if bcp is not a basic */
102     /* code point.                                                   */
103
104     private static char encode_basic(int bcp, int flag)
105     {
106       bcp -= (((bcp - 97) < 26) ? 1 :0 ) << 5;
107       boolean mybcp = (bcp - 65 < 26);
108       return (char) (bcp + (((flag==0) && mybcp ) ? 1 : 0 ) << 5);
109     }
110
111     /*** Platform-specific constants ***/
112
113     /* maxint is the maximum value of a punycode_uint variable: */
114     private static long maxint = 0xFFFFFFFFL;
115     /* Because maxint is unsigned, -1 becomes the maximum value. */
116
117     /*** Bias adaptation function ***/
118
119     private static int adapt(int delta, int numpoints, boolean firsttime ){
120       int k;
121
122       delta = (firsttime==true) ? delta / damp : delta >> 1;
123       /* delta >> 1 is a faster way of doing delta / 2 */
124       delta += delta / numpoints;
125
126       for (k = 0;  delta > ((base - tmin) * tmax) / 2;  k += base) {
127         delta /= base - tmin;
128       }
129
130       return k + (base - tmin + 1) * delta / (delta + skew);
131     }
132
133     /*** Main encode function ***/
134
135     public static final int encode(   int input_length,
136                                       int input[],
137                                       char[] case_flags,
138                                       int[] output_length,
139                                       char output[] ){
140       int delta, h, b, out, max_out, bias, j, q, k, t;
141       long m,n;
142       /* Initialize the state: */
143
144       n = initial_n;
145       delta = out = 0;
146       max_out = output_length[0];
147       bias = initial_bias;
148
149       /* Handle the basic code points: */
150
151       for (j = 0;  j < input_length;  ++j) {
152         if (basic(input[j])) {
153           if (max_out - out < 2) return punycode_big_output;
154           output[out++] = (char)
155             (case_flags!=null ?  encode_basic(input[j], case_flags[j]) : input[j]);
156         }
157         /* else if (input[j] < n) return punycode_bad_input; */
158         /* (not needed for Punycode with unsigned code points) */
159       }
160
161       h = b = out;
162
163       /* h is the number of code points that have been handled, b is the  */
164       /* number of basic code points, and out is the number of characters */
165       /* that have been output.                                           */
166
167       if (b > 0) output[out++] = delimiter;
168
169       /* Main encoding loop: */
170
171       while (h < input_length) {
172         /* All non-basic code points < n have been     */
173         /* handled already.  Find the next larger one: */
174
175         for (m = maxint, j = 0;  j < input_length;  ++j) {
176           /* if (basic(input[j])) continue; */
177           /* (not needed for Punycode) */
178           if (input[j] >= n && input[j] < m) m = input[j];
179         }
180
181         /* Increase delta enough to advance the decoder's    */
182         /* <n,i> state to <m,0>, but guard against overflow: */
183
184         if (m - n > (maxint - delta) / (h + 1)) return punycode_overflow;
185         delta += (m - n) * (h + 1);
186         n = m;
187
188         for (j = 0;  j < input_length;  ++j) {
189           /* Punycode does not need to check whether input[j] is basic: */
190           if (input[j] < n /* || basic(input[j]) */ ) {
191             if (++delta == 0) return punycode_overflow;
192           }
193
194           if (input[j] == n) {
195             /* Represent delta as a generalized variable-length integer: */
196
197             for (q = delta, k = base;  ;  k += base) {
198               if (out >= max_out) return punycode_big_output;
199               t = k <= bias /* + tmin */ ? tmin :     /* +tmin not needed */
200                   k >= bias + tmax ? tmax : k - bias;
201               if (q < t) break;
202               output[out++] = encode_digit(t + (q - t) % (base - t), 0);
203               q = (q - t) / (base - t);
204             }
205
206             output[out++] = encode_digit(q, (case_flags !=null) ? case_flags[j] : 0);
207             bias = adapt(delta, h + 1, (h == b));
208             delta = 0;
209             ++h;
210           }
211         }
212
213         ++delta;
214         ++n;
215       }
216
217       output_length[0] = out;
218       return punycode_success;
219     }
220     
221     public static final StringBuffer encode(StringBuffer input,char[] case_flags)
222                                throws StringPrepParseException{
223         int[] in = new int[input.length()];
224         int inLen = 0;
225         int ch;
226         StringBuffer result = new StringBuffer();
227         UCharacterIterator iter = UCharacterIterator.getInstance(input);
228         while((ch=iter.nextCodePoint())!= UCharacterIterator.DONE){
229             in[inLen++]=ch;
230         }
231
232         int[] outLen =  new int[1];
233         outLen[0] = input.length()*4;
234         char[] output = new char[outLen[0]];
235         int rc = punycode_success;
236         for(;;){
237             rc = encode(inLen,in,case_flags, outLen, output);
238             if(rc==punycode_big_output){
239                 outLen[0] = outLen[0]*4;
240                 output = new char[outLen[0]];
241                 // continue to convert
242                 continue;
243             }
244             break;
245         }
246         if(rc==punycode_success){
247             return result.append(output,0,outLen[0]);
248         }
249         getException(rc);
250         return result;
251     }
252
253     private static void getException(int rc) 
254                    throws StringPrepParseException{
255          switch(rc){
256              case punycode_big_output:
257                 throw new StringPrepParseException("The output capacity was not sufficient.",StringPrepParseException.BUFFER_OVERFLOW_ERROR);
258              case punycode_bad_input:
259                 throw new StringPrepParseException("Illegal char found in the input",StringPrepParseException.ILLEGAL_CHAR_FOUND);
260              case punycode_overflow:
261                 throw new StringPrepParseException("Invalid char found in the input",StringPrepParseException.INVALID_CHAR_FOUND);   
262          }
263         
264     }
265     private static final int MAX_BUFFER_SIZE = 100;
266     
267     public static final StringBuffer decode(StringBuffer input,char[] case_flags)
268                                throws StringPrepParseException{
269         char[] in = input.toString().toCharArray();
270         int[] outLen = new int[1];
271         outLen[0] = MAX_BUFFER_SIZE;
272         int[] output = new int[outLen[0]];
273         int rc = punycode_success;
274         StringBuffer result = new StringBuffer();
275         for(;;){
276             rc = decode(input.length(),in, outLen, output,case_flags);
277             if(rc==punycode_big_output){
278                 outLen[0] = output.length * 4;
279                 output = new int[outLen[0]];
280                 continue;
281             }
282             break;
283         }
284         if(rc==punycode_success){
285             for(int i=0; i < outLen[0]; i++ ){
286                 UTF16.append(result,output[i]);
287             }
288         }else{
289             getException(rc);
290         }
291         return result;
292     }
293     
294     /*** Main decode function ***/
295     public static final int decode(int input_length,
296                              char[] input,
297                              int[] output_length,
298                              int[] output,
299                              char[] case_flags ){
300       int n, out, i, max_out, bias,
301                      b, j, in, oldi, w, k, digit, t;
302
303       /* Initialize the state: */
304
305       n = initial_n;
306       out = i = 0;
307       max_out = output_length[0];
308       bias = initial_bias;
309
310       /* Handle the basic code points:  Let b be the number of input code */
311       /* points before the last delimiter, or 0 if there is none, then    */
312       /* copy the first b code points to the output.                      */
313
314       for (b = j = 0;  j < input_length;  ++j){
315            if (delim(input[j])==true){
316                 b = j;
317            }
318       }
319       if (b > max_out) return punycode_big_output;
320
321       for (j = 0;  j < b;  ++j) {
322         if (case_flags != null) case_flags[out] = (char)(flagged(input[j]) ? 1 : 0);
323         if (!basic(input[j])) return punycode_bad_input;
324         output[out++] = input[j];
325       }
326
327       /* Main decoding loop:  Start just after the last delimiter if any  */
328       /* basic code points were copied; start at the beginning otherwise. */
329
330       for (in = b > 0 ? b + 1 : 0;  in < input_length;  ++out) {
331
332         /* in is the index of the next character to be consumed, and */
333         /* out is the number of code points in the output array.     */
334
335         /* Decode a generalized variable-length integer into delta,  */
336         /* which gets added to i.  The overflow checking is easier   */
337         /* if we increase i as we go, then subtract off its starting */
338         /* value at the end to obtain delta.                         */
339
340         for (oldi = i, w = 1, k = base;  ;  k += base) {
341           if (in >= input_length) return punycode_bad_input;
342           digit = decode_digit(input[in++]);
343           if (digit >= base) return punycode_bad_input;
344           if (digit > (maxint - i) / w) return punycode_overflow;
345           i += digit * w;
346           t = (k <= bias) /* + tmin */ ? tmin :     /* +tmin not needed */
347               (k >= (bias + tmax)) ? tmax : k - bias;
348           if (digit < t) break;
349           if (w > maxint / (base - t)) return punycode_overflow;
350           w *= (base - t);
351         }
352
353         bias = adapt(i - oldi, out + 1, (oldi == 0));
354
355         /* i was supposed to wrap around from out+1 to 0,   */
356         /* incrementing n each time, so we'll fix that now: */
357
358         if (i / (out + 1) > maxint - n) return punycode_overflow;
359         n += i / (out + 1);
360         i %= (out + 1);
361
362         /* Insert n at position i of the output: */
363
364         /* not needed for Punycode: */
365         /* if (decode_digit(n) <= base) return punycode_invalid_input; */
366         if (out >= max_out) return punycode_big_output;
367
368         if (case_flags != null) {
369           System.arraycopy(case_flags, i, case_flags,  i + 1, out - i);
370           /* Case of last character determines uppercase flag: */
371           case_flags[i] = (char)(flagged(input[in - 1]) ? 0 :1);
372         }
373
374         System.arraycopy(output, i, output, i + 1,  (out - i));
375         output[i++] = n;
376       }
377
378       output_length[0] = out;
379       return punycode_success;
380     }
381
382 }