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