]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_8_1_1/main/classes/charset/src/com/ibm/icu/charset/CharsetCallback.java
Added flags.
[Dictionary.git] / jars / icu4j-4_8_1_1 / main / classes / charset / src / com / ibm / icu / charset / CharsetCallback.java
1 /**
2 *******************************************************************************
3 * Copyright (C) 2006-2011, International Business Machines Corporation and    *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 *
7 *******************************************************************************
8 */ 
9
10 package com.ibm.icu.charset;
11
12 import java.nio.ByteBuffer;
13 import java.nio.CharBuffer;
14 import java.nio.IntBuffer;
15 import java.nio.charset.CoderResult;
16
17 /**
18  * <h2> Callback API for CharsetICU API </h2>
19  * 
20  *  CharsetCallback class defines some error behaviour functions called 
21  *  by CharsetDecoderICU and CharsetEncoderICU. The class also provides
22  *  the facility by which clients can write their own callbacks.
23  *
24  *  These functions, although public, should NEVER be called directly.
25  *  They should be used as parameters to the onUmappableCharacter() and 
26  *  onMalformedInput() methods, to set the behaviour of a converter
27  *  when it encounters UNMAPPED/INVALID sequences.
28  *  Currently the only way to set callbacks is by using CodingErrorAction.
29  *  In the future we will provide set methods on CharsetEncoder and CharsetDecoder
30  *  that will accept CharsetCallback fields.
31  *
32  * @stable ICU 3.6
33  */
34
35 public class CharsetCallback {
36     /*
37      * FROM_U, TO_U context options for sub callback
38      */
39     private static final String SUB_STOP_ON_ILLEGAL = "i";
40
41 //    /*
42 //     * FROM_U, TO_U context options for skip callback
43 //     */
44 //    private static final String SKIP_STOP_ON_ILLEGAL = "i";
45
46 //    /*
47 //     * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to ICU (%UXXXX) 
48 //     */
49 //    private static final String ESCAPE_ICU  = null;
50
51     /*
52      * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to JAVA (\\uXXXX)
53      */
54     private static final String ESCAPE_JAVA     =  "J";
55
56     /*
57      * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to C (\\uXXXX \\UXXXXXXXX)
58      * TO_U_CALLBACK_ESCAPE option to escape the character value accoding to C (\\xXXXX)
59      */
60     private static final String ESCAPE_C        = "C";
61
62     /*
63      * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to XML Decimal escape \htmlonly(&amp;#DDDD;)\endhtmlonly
64      * TO_U_CALLBACK_ESCAPE context option to escape the character value accoding to XML Decimal escape \htmlonly(&amp;#DDDD;)\endhtmlonly
65      */
66     private static final String ESCAPE_XML_DEC  = "D";
67
68     /*
69      * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to XML Hex escape \htmlonly(&amp;#xXXXX;)\endhtmlonly
70      * TO_U_CALLBACK_ESCAPE context option to escape the character value according to XML Hex escape \htmlonly(&amp;#xXXXX;)\endhtmlonly
71      */
72     private static final String ESCAPE_XML_HEX  = "X";
73
74     /*
75      * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to Unicode (U+XXXXX)
76      */
77     private static final String ESCAPE_UNICODE  = "U";
78
79     /*
80      * FROM_U_CALLBACK_ESCAPE context option to escape the code unit according to Unicode (U+XXXXX)
81      */
82     private static final String ESCAPE_CSS2  = "S";
83
84     /**
85      * Decoder Callback interface
86      * @stable ICU 3.6
87      */
88     public interface Decoder {
89         /**
90          * This function is called when the bytes in the source cannot be handled,
91          * and this function is meant to handle or fix the error if possible.
92          * 
93          * @return Result of decoding action. This returned object is set to an error
94          *  if this function could not handle the conversion.
95          * @stable ICU 3.6
96          */
97         public CoderResult call(CharsetDecoderICU decoder, Object context, 
98                                 ByteBuffer source, CharBuffer target, IntBuffer offsets,
99                                 char[] buffer, int length, CoderResult cr);
100     }
101     /**
102      * Encoder Callback interface
103      * @stable ICU 3.6
104      */
105     public interface Encoder {
106         /**
107          * This function is called when the Unicode characters in the source cannot be handled,
108          * and this function is meant to handle or fix the error if possible.
109          * @return Result of decoding action. This returned object is set to an error
110          *  if this function could not handle the conversion.
111          * @stable ICU 3.6
112          */
113         public CoderResult call(CharsetEncoderICU encoder, Object context, 
114                                 CharBuffer source, ByteBuffer target, IntBuffer offsets, 
115                                 char[] buffer, int length, int cp, CoderResult cr);
116     }    
117     /**
118      * Skip callback
119      * @stable ICU 3.6
120      */
121     public static final Encoder FROM_U_CALLBACK_SKIP = new Encoder() {
122         public CoderResult call(CharsetEncoderICU encoder, Object context, 
123                 CharBuffer source, ByteBuffer target, IntBuffer offsets, 
124                 char[] buffer, int length, int cp, CoderResult cr){
125             if(context==null){
126                 return CoderResult.UNDERFLOW;
127             }else if(((String)context).equals(SUB_STOP_ON_ILLEGAL)){
128                 if(!cr.isUnmappable()){
129                     return cr;
130                 }else{
131                     return CoderResult.UNDERFLOW;
132                 }
133             }
134             return cr;
135         }
136     };
137     /**
138      * Skip callback
139      * @stable ICU 3.6
140      */
141     public static final Decoder TO_U_CALLBACK_SKIP = new Decoder() {
142         public CoderResult call(CharsetDecoderICU decoder, Object context, 
143                 ByteBuffer source, CharBuffer target, IntBuffer offsets,
144                 char[] buffer, int length, CoderResult cr){
145             if(context==null){
146                 return CoderResult.UNDERFLOW;
147             }else if(((String)context).equals(SUB_STOP_ON_ILLEGAL)){
148                 if(!cr.isUnmappable()){
149                     return cr;
150                 }else{
151                     return CoderResult.UNDERFLOW;
152                 }
153             }
154             return cr;
155         }
156     };
157     /**
158      * Write substitute callback
159      * @stable ICU 3.6
160      */
161     public static final Encoder FROM_U_CALLBACK_SUBSTITUTE = new Encoder(){        
162         public CoderResult call(CharsetEncoderICU encoder, Object context, 
163                 CharBuffer source, ByteBuffer target, IntBuffer offsets, 
164                 char[] buffer, int length, int cp, CoderResult cr){
165             if(context==null){
166                 return encoder.cbFromUWriteSub(encoder, source, target, offsets);
167             }else if(((String)context).equals(SUB_STOP_ON_ILLEGAL)){
168                 if(!cr.isUnmappable()){
169                     return cr;
170                 }else{
171                    return encoder.cbFromUWriteSub(encoder, source, target, offsets);
172                 }
173             }
174             return cr;
175         }
176     };
177     private static final char[] kSubstituteChar1 = new char[]{0x1A};
178     private static final char[] kSubstituteChar = new char[] {0xFFFD};
179     /**
180      * Write substitute callback
181      * @stable ICU 3.6
182      */
183     public static final Decoder TO_U_CALLBACK_SUBSTITUTE  = new Decoder() {
184         public CoderResult call(CharsetDecoderICU decoder, Object context, 
185                 ByteBuffer source, CharBuffer target, IntBuffer offsets,
186                 char[] buffer, int length, CoderResult cr){
187
188             CharsetICU cs = (CharsetICU) decoder.charset();
189             /* Use the specified replacement character if it is different than the default one. */
190             boolean useReplacement = true;
191             char [] replacementChar = decoder.replacement().toCharArray();
192             if (replacementChar.length == 1 && (replacementChar[0] == kSubstituteChar1[0] || replacementChar[0] == kSubstituteChar[0])) {
193                 useReplacement = false;
194             }
195             
196             /* could optimize this case, just one uchar */
197             if(decoder.invalidCharLength == 1 && cs.subChar1 != 0) {
198                 return CharsetDecoderICU.toUWriteUChars(decoder, useReplacement ? replacementChar : kSubstituteChar1, 0, useReplacement ? replacementChar.length : 1, target, offsets, source.position());
199             } else {
200                 return CharsetDecoderICU.toUWriteUChars(decoder, useReplacement ? replacementChar : kSubstituteChar, 0, useReplacement ? replacementChar.length : 1, target, offsets, source.position());
201             }
202         }
203     };
204     /**
205      * Stop callback
206      * @stable ICU 3.6
207      */
208     public static final Encoder FROM_U_CALLBACK_STOP = new Encoder() {
209         public CoderResult call(CharsetEncoderICU encoder, Object context, 
210                 CharBuffer source, ByteBuffer target, IntBuffer offsets, 
211                 char[] buffer, int length, int cp, CoderResult cr){
212             return cr;
213         }
214     };
215     /**
216      * Stop callback
217      * @stable ICU 3.6
218      */
219     public static final Decoder TO_U_CALLBACK_STOP = new Decoder() {
220         public CoderResult call(CharsetDecoderICU decoder, Object context, 
221                 ByteBuffer source, CharBuffer target, IntBuffer offsets,
222                 char[] buffer, int length, CoderResult cr){
223             return cr;
224         }
225     };  
226     private static final int VALUE_STRING_LENGTH = 32;
227     private static final char UNICODE_PERCENT_SIGN_CODEPOINT    = 0x0025;
228     private static final char UNICODE_U_CODEPOINT               = 0x0055;
229     private static final char UNICODE_X_CODEPOINT               = 0x0058;
230     private static final char UNICODE_RS_CODEPOINT              = 0x005C;
231     private static final char UNICODE_U_LOW_CODEPOINT           = 0x0075;
232     private static final char UNICODE_X_LOW_CODEPOINT           = 0x0078;
233     private static final char UNICODE_AMP_CODEPOINT             = 0x0026;
234     private static final char UNICODE_HASH_CODEPOINT            = 0x0023;
235     private static final char UNICODE_SEMICOLON_CODEPOINT       = 0x003B;
236     private static final char UNICODE_PLUS_CODEPOINT            = 0x002B;
237     private static final char UNICODE_LEFT_CURLY_CODEPOINT      = 0x007B;
238     private static final char UNICODE_RIGHT_CURLY_CODEPOINT     = 0x007D;
239     private static final char UNICODE_SPACE_CODEPOINT           = 0x0020;
240     /**
241      * Write escape callback
242      * @stable ICU 4.0
243      */
244     public static final Encoder FROM_U_CALLBACK_ESCAPE = new Encoder() {
245         public CoderResult call(CharsetEncoderICU encoder, Object context, 
246                 CharBuffer source, ByteBuffer target, IntBuffer offsets, 
247                 char[] buffer, int length, int cp, CoderResult cr){
248             char[] valueString = new char[VALUE_STRING_LENGTH];
249             int valueStringLength = 0;
250             int i = 0;
251             
252             cr = CoderResult.UNDERFLOW;
253             
254             if (context == null || !(context instanceof String)) {
255                 while (i < length) {
256                     valueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT; /* adding % */
257                     valueString[valueStringLength++] = UNICODE_U_CODEPOINT; /* adding U */
258                     valueStringLength += itou(valueString, valueStringLength, (int)buffer[i++] & UConverterConstants.UNSIGNED_SHORT_MASK, 16, 4);
259                 }
260             } else {
261                 if (((String)context).equals(ESCAPE_JAVA)) {
262                     while (i < length) {
263                         valueString[valueStringLength++] = UNICODE_RS_CODEPOINT;    /* adding \ */
264                         valueString[valueStringLength++] = UNICODE_U_LOW_CODEPOINT; /* adding u */
265                         valueStringLength += itou(valueString, valueStringLength, (int)buffer[i++] & UConverterConstants.UNSIGNED_SHORT_MASK, 16, 4);
266                     }
267                 } else if (((String)context).equals(ESCAPE_C)) {
268                     valueString[valueStringLength++] = UNICODE_RS_CODEPOINT;    /* adding \ */
269                     
270                     if (length == 2) {
271                         valueString[valueStringLength++] = UNICODE_U_CODEPOINT; /* adding U */
272                         valueStringLength = itou(valueString, valueStringLength, cp, 16, 8);
273                     } else {
274                         valueString[valueStringLength++] = UNICODE_U_LOW_CODEPOINT; /* adding u */
275                         valueStringLength += itou(valueString, valueStringLength, (int)buffer[0] & UConverterConstants.UNSIGNED_SHORT_MASK, 16, 4);
276                     }
277                 } else if (((String)context).equals(ESCAPE_XML_DEC)) {
278                     valueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;   /* adding & */
279                     valueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;  /* adding # */
280                     if (length == 2) {
281                         valueStringLength += itou(valueString, valueStringLength, cp, 10, 0);
282                     } else {
283                         valueStringLength += itou(valueString, valueStringLength, (int)buffer[0] & UConverterConstants.UNSIGNED_SHORT_MASK, 10, 0);
284                     }
285                     valueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
286                 } else if (((String)context).equals(ESCAPE_XML_HEX)) {
287                     valueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;   /* adding & */
288                     valueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;  /* adding # */
289                     valueString[valueStringLength++] = UNICODE_X_LOW_CODEPOINT; /* adding x */
290                     if (length == 2) {
291                         valueStringLength += itou(valueString, valueStringLength, cp, 16, 0);
292                     } else {
293                         valueStringLength += itou(valueString, valueStringLength, (int)buffer[0] & UConverterConstants.UNSIGNED_SHORT_MASK, 16, 0);
294                     }
295                     valueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT; /* adding ; */
296                 } else if (((String)context).equals(ESCAPE_UNICODE)) {
297                     valueString[valueStringLength++] = UNICODE_LEFT_CURLY_CODEPOINT;    /* adding { */
298                     valueString[valueStringLength++] = UNICODE_U_CODEPOINT;             /* adding U */
299                     valueString[valueStringLength++] = UNICODE_PLUS_CODEPOINT;          /* adding + */
300                     if (length == 2) {
301                         valueStringLength += itou(valueString, valueStringLength,cp, 16, 4);
302                     } else {
303                         valueStringLength += itou(valueString, valueStringLength, (int)buffer[0] & UConverterConstants.UNSIGNED_SHORT_MASK, 16, 4);
304                     }
305                     valueString[valueStringLength++] = UNICODE_RIGHT_CURLY_CODEPOINT;   /* adding } */
306                 } else if (((String)context).equals(ESCAPE_CSS2)) {
307                     valueString[valueStringLength++] = UNICODE_RS_CODEPOINT;    /* adding \ */
308                     valueStringLength += itou(valueString, valueStringLength, cp, 16, 0);
309                     /* Always add space character, because the next character might be whitespace,
310                        which would erroneously be considered the termination of the escape sequence. */
311                     valueString[valueStringLength++] = UNICODE_SPACE_CODEPOINT;
312                 } else {
313                     while (i < length) {
314                         valueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT;  /* adding % */
315                         valueString[valueStringLength++] = UNICODE_U_CODEPOINT;             /* adding U */
316                         valueStringLength += itou(valueString, valueStringLength, (int)buffer[i++] & UConverterConstants.UNSIGNED_SHORT_MASK, 16, 4);
317                     }
318                 }
319             }
320
321             cr = encoder.cbFromUWriteUChars(encoder, CharBuffer.wrap(valueString, 0, valueStringLength), target, offsets);
322             return cr;
323         }
324     };
325     /**
326      * Write escape callback
327      * @stable ICU 4.0
328      */
329     public static final Decoder TO_U_CALLBACK_ESCAPE = new Decoder() {
330         public CoderResult call(CharsetDecoderICU decoder, Object context, 
331                 ByteBuffer source, CharBuffer target, IntBuffer offsets,
332                 char[] buffer, int length, CoderResult cr){
333             char[] uniValueString = new char[VALUE_STRING_LENGTH];
334             int valueStringLength = 0;
335             int i = 0;
336             
337             if (context == null || !(context instanceof String)) {
338                 while (i < length) {
339                     uniValueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT;   /* adding % */
340                     uniValueString[valueStringLength++] = UNICODE_X_CODEPOINT;              /* adding U */
341                     valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 2);
342                 }
343             } else {
344                 if (((String)context).equals(ESCAPE_XML_DEC)) {
345                     while (i < length) {
346                         uniValueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;    /* adding & */
347                         uniValueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;   /* adding # */
348                         valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 10, 0);
349                         uniValueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT;  /* adding ; */
350                     }
351                 } else if (((String)context).equals(ESCAPE_XML_HEX)) {
352                     while (i < length) {
353                         uniValueString[valueStringLength++] = UNICODE_AMP_CODEPOINT;    /* adding & */
354                         uniValueString[valueStringLength++] = UNICODE_HASH_CODEPOINT;   /* adding # */
355                         uniValueString[valueStringLength++] = UNICODE_X_LOW_CODEPOINT;  /* adding x */
356                         valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 0);
357                         uniValueString[valueStringLength++] = UNICODE_SEMICOLON_CODEPOINT;  /* adding ; */
358                     }
359                 } else if (((String)context).equals(ESCAPE_C)) {
360                     while (i < length) {
361                         uniValueString[valueStringLength++] = UNICODE_RS_CODEPOINT;         /* adding \ */
362                         uniValueString[valueStringLength++] = UNICODE_X_LOW_CODEPOINT;      /* adding x */
363                         valueStringLength += itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 2);
364                     }
365                 } else {
366                     while (i < length) {
367                         uniValueString[valueStringLength++] = UNICODE_PERCENT_SIGN_CODEPOINT;   /* adding % */
368                         uniValueString[valueStringLength++] = UNICODE_X_CODEPOINT;              /* adding X */
369                         itou(uniValueString, valueStringLength, buffer[i++] & UConverterConstants.UNSIGNED_BYTE_MASK, 16, 2);
370                         valueStringLength += 2;
371                     }
372                 }
373             }
374             
375             cr = CharsetDecoderICU.toUWriteUChars(decoder, uniValueString, 0, valueStringLength, target, offsets, 0);
376             
377             return cr;
378         }
379     };  
380     /***
381      * Java port of uprv_itou() in ICU4C used by TO_U_CALLBACK_ESCAPE and FROM_U_CALLBACK_ESCAPE.
382      * Fills in a char string with the radix-based representation of a number padded with zeroes
383      * to minwidth.
384      */
385     private static final int itou(char[] buffer, int sourceIndex, int i, int radix, int minwidth) {
386         int length = 0;
387         int digit;
388         int j;
389         char temp;
390         
391         do {
392             digit = i % radix;
393             buffer[sourceIndex + length++] = (char)(digit <= 9 ? (0x0030+digit) : (0x0030+digit+7));
394             i = i/radix;
395         } while (i != 0 && (sourceIndex + length) < buffer.length);
396         
397         while (length < minwidth) {
398             buffer[sourceIndex + length++] = (char)0x0030; /* zero padding */
399         }
400         /* reverses the string */
401         for (j = 0; j < (length / 2); j++) {
402             temp = buffer[(sourceIndex + length - 1) - j];
403             buffer[(sourceIndex + length-1) -j] = buffer[sourceIndex + j];
404             buffer[sourceIndex + j] = temp;
405         }
406         
407         return length;
408     }
409
410     /*
411      * No need to create an instance
412      */
413     private CharsetCallback() {
414     }
415 }