CharsetICU.java revision c60bc1815dca549f3fb4e572f6aac749d7fa9fc6
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*******************************************************************************
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* Copyright (C) 1996-2005, International Business Machines Corporation and    *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* others. All Rights Reserved.                                                *
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*******************************************************************************
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*******************************************************************************
8ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes*/
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage com.ibm.icu4jni.charset;
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.Charset;
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.CharsetDecoder;
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.CharsetEncoder;
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap;
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map;
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18ebe438a0734f24ded1772778e5e712c820981234Elliott Hughespublic final class CharsetICU extends Charset {
19c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    private static final Map<String, byte[]> DEFAULT_REPLACEMENTS = new HashMap<String, byte[]>();
20c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    static {
21c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // ICU has different default replacements to the RI in these cases. There are probably
22c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // more cases too, but this covers all the charsets that Java guarantees will be available.
23c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // These use U+FFFD REPLACEMENT CHARACTER...
24c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        DEFAULT_REPLACEMENTS.put("UTF-16",   new byte[] { (byte) 0xff, (byte) 0xfd });
25c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        DEFAULT_REPLACEMENTS.put("UTF-32",   new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0xff, (byte) 0xfd });
26c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // These use '?'. It's odd that UTF-8 doesn't use U+FFFD, given that (unlike ISO-8859-1
27c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // and US-ASCII) it can represent it, but this is what the RI does...
28c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        byte[] questionMark = new byte[] { (byte) '?' };
29c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        DEFAULT_REPLACEMENTS.put("UTF-8",      questionMark);
30c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        DEFAULT_REPLACEMENTS.put("ISO-8859-1", questionMark);
31c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        DEFAULT_REPLACEMENTS.put("US-ASCII",   questionMark);
32c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    }
33c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes
34bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private final String icuCanonicalName;
35c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    protected CharsetICU(String canonicalName, String icuCanonName, String[] aliases) {
37bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes         super(canonicalName, aliases);
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         icuCanonicalName = icuCanonName;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
40c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes
41bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    public CharsetDecoder newDecoder() {
42c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        return new CharsetDecoderICU(this, NativeConverter.openConverter(icuCanonicalName));
43bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    }
44ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes
45ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes    public CharsetEncoder newEncoder() {
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long converterHandle = NativeConverter.openConverter(icuCanonicalName);
47c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        // We have our own map of RI-compatible default replacements...
48c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        byte[] replacement = DEFAULT_REPLACEMENTS.get(icuCanonicalName);
49c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (replacement == null) {
50c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            // ...but fall back to asking ICU.
51c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            // TODO: should we just try to use U+FFFD and fall back to '?' if U+FFFD can't be encoded?
52c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            replacement = NativeConverter.getSubstitutionBytes(converterHandle);
53c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        } else {
54c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            replacement = replacement.clone();
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
56c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        return new CharsetEncoderICU(this, converterHandle, replacement);
57ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes    }
58ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes
59c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes    public boolean contains(Charset cs) {
60c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes        if (cs == null) {
61c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes            return false;
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else if (this.equals(cs)) {
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
65ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long converterHandle1 = 0;
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        long converterHandle2 = 0;
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            converterHandle1 = NativeConverter.openConverter(this.name());
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (converterHandle1 > 0) {
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                converterHandle2 = NativeConverter.openConverter(cs.name());
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (converterHandle2 > 0) {
74c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes                    return NativeConverter.contains(converterHandle1, converterHandle2);
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (0 != converterHandle1) {
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                NativeConverter.closeConverter(converterHandle1);
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (0 != converterHandle2) {
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    NativeConverter.closeConverter(converterHandle2);
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
88