1/**
2*******************************************************************************
3* Copyright (C) 1996-2005, International Business Machines Corporation and    *
4* others. All Rights Reserved.                                                *
5*******************************************************************************
6*
7*******************************************************************************
8*/
9
10package com.ibm.icu4jni.charset;
11
12import java.nio.charset.Charset;
13import java.nio.charset.CharsetDecoder;
14import java.nio.charset.CharsetEncoder;
15import java.util.HashMap;
16import java.util.Map;
17
18// BEGIN android-removed
19// import com.ibm.icu4jni.common.ErrorCode;
20// import com.ibm.icu4jni.converters.NativeConverter;
21// END android-removed
22
23
24public final class CharsetICU extends Charset{
25    private String icuCanonicalName;
26    /**
27     * Constructor to create a the CharsetICU object
28     * @param canonicalName the canonical name as a string
29     * @param aliases the alias set as an array of strings
30     * @stable ICU 2.4
31     */
32    protected CharsetICU(String canonicalName, String icuCanonName, String[] aliases) {
33         super(canonicalName,aliases);
34         icuCanonicalName = icuCanonName;
35
36    }
37    /**
38     * Returns a new decoder instance of this charset object
39     * @return a new decoder object
40     * @stable ICU 2.4
41     */
42    public CharsetDecoder newDecoder(){
43        // the arrays are locals and not
44        // instance variables since the
45        // methods on this class need to
46        // be thread safe
47        long converterHandle = NativeConverter.openConverter(icuCanonicalName);
48        return new CharsetDecoderICU(this,converterHandle);
49    };
50
51    // hardCoded list of replacement bytes
52    private static final Map subByteMap = new HashMap();
53    static{
54        subByteMap.put("UTF-32",new byte[]{0x00, 0x00, (byte)0xfe, (byte)0xff});
55        subByteMap.put("ibm-16684_P110-2003",new byte[]{0x40, 0x40}); // make \u3000 the sub char
56        subByteMap.put("ibm-971_P100-1995",new byte[]{(byte)0xa1, (byte)0xa1}); // make \u3000 the sub char
57    }
58    /**
59     * Returns a new encoder object of the charset
60     * @return a new encoder
61     * @stable ICU 2.4
62     */
63    public CharsetEncoder newEncoder(){
64        // the arrays are locals and not
65        // instance variables since the
66        // methods on this class need to
67        // be thread safe
68        long converterHandle = NativeConverter.openConverter(icuCanonicalName);
69
70        //According to the contract all converters should have non-empty replacement
71        byte[] replacement = NativeConverter.getSubstitutionBytes(converterHandle);
72
73       try{
74            return new CharsetEncoderICU(this,converterHandle, replacement);
75        }catch(IllegalArgumentException ex){
76            // work around for the non-sensical check in the nio API that
77            // a substitution character must be mappable while decoding!!
78            replacement = (byte[])subByteMap.get(icuCanonicalName);
79            if(replacement==null){
80                replacement = new byte[NativeConverter.getMinBytesPerChar(converterHandle)];
81                for(int i=0; i<replacement.length; i++){
82                    replacement[i]= 0x3f;
83                }
84            }
85            NativeConverter.setSubstitutionBytes(converterHandle, replacement, replacement.length);
86            return new CharsetEncoderICU(this,converterHandle, replacement);
87        }
88    }
89
90    /**
91     * Ascertains if a charset is a sub set of this charset
92     * @param cs charset to test
93     * @return true if the given charset is a subset of this charset
94     * @stable ICU 2.4
95     *
96     * //CSDL: major changes by Jack
97     */
98    public boolean contains(Charset cs){
99        if (null == cs) {
100        return false;
101        } else if (this.equals(cs)) {
102            return true;
103        }
104
105        long converterHandle1 = 0;
106        long converterHandle2 = 0;
107
108        try {
109            converterHandle1 = NativeConverter.openConverter(this.name());
110            if (converterHandle1 > 0) {
111                converterHandle2 = NativeConverter.openConverter(cs.name());
112                if (converterHandle2 > 0) {
113                    return NativeConverter.contains(converterHandle1,
114                            converterHandle2);
115                }
116            }
117            return false;
118        } finally {
119            if (0 != converterHandle1) {
120                NativeConverter.closeConverter(converterHandle1);
121                if (0 != converterHandle2) {
122                    NativeConverter.closeConverter(converterHandle2);
123                }
124            }
125        }
126    }
127}
128
129
130