summaryrefslogtreecommitdiff
path: root/android_icu4j/src/main/java/android/icu/impl/ICUData.java
blob: 34b8323a4688cb8446645e2f9934863dc39d154f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/* GENERATED SOURCE. DO NOT MODIFY. */
/*
 *******************************************************************************
 * Copyright (C) 2004-2014, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 *
 * Created on Feb 4, 2004
 *
 */
package android.icu.impl;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.MissingResourceException;
import java.util.logging.Logger;

import android.icu.util.VersionInfo;

/**
 * Provides access to ICU data files as InputStreams.  Implements security checking.
 * @hide Only a subset of ICU is exposed in Android
 */
public final class ICUData {
    /**
     * The data path to be used with getBundleInstance API
     */
    static final String ICU_DATA_PATH = "android/icu/impl/";
    /**
     * The ICU data package name.
     * This is normally the name of the .dat package, and the prefix (plus '/')
     * of the package entry names.
     */
    static final String PACKAGE_NAME = "icudt" + VersionInfo.ICU_DATA_VERSION_PATH;
    /**
     * The data path to be used with Class.getResourceAsStream().
     */
    public static final String ICU_BUNDLE = "data/" + PACKAGE_NAME;

    /**
     * The base name of ICU data to be used with ClassLoader.getResourceAsStream(),
     * ICUResourceBundle.getBundleInstance() etc.
     */
    public static final String ICU_BASE_NAME = ICU_DATA_PATH + ICU_BUNDLE;

    /**
     * The base name of collation data to be used with getBundleInstance API
     */
    public static final String ICU_COLLATION_BASE_NAME = ICU_BASE_NAME + "/coll";

    /**
     * The base name of rbbi data to be used with getData API
     */
    public static final String ICU_BRKITR_NAME = "brkitr";

    /**
     * The base name of rbbi data to be used with getBundleInstance API
     */
    public static final String ICU_BRKITR_BASE_NAME = ICU_BASE_NAME + '/' + ICU_BRKITR_NAME;

    /**
     * The base name of rbnf data to be used with getBundleInstance API
     */
    public static final String ICU_RBNF_BASE_NAME = ICU_BASE_NAME + "/rbnf";

    /**
     * The base name of transliterator data to be used with getBundleInstance API
     */
    public static final String ICU_TRANSLIT_BASE_NAME = ICU_BASE_NAME + "/translit";

    public static final String ICU_LANG_BASE_NAME = ICU_BASE_NAME + "/lang";
    public static final String ICU_CURR_BASE_NAME = ICU_BASE_NAME + "/curr";
    public static final String ICU_REGION_BASE_NAME = ICU_BASE_NAME + "/region";
    public static final String ICU_ZONE_BASE_NAME = ICU_BASE_NAME + "/zone";
    public static final String ICU_UNIT_BASE_NAME = ICU_BASE_NAME + "/unit";

    /**
     * For testing (otherwise false): When reading an InputStream from a Class or ClassLoader
     * (that is, not from a file), log when the stream contains ICU binary data.
     *
     * This cannot be ICUConfig'ured because ICUConfig calls ICUData.getStream()
     * to read the properties file, so we would get a circular dependency
     * in the class initialization.
     */
    private static final boolean logBinaryDataFromInputStream = false;
    private static final Logger logger = logBinaryDataFromInputStream ?
            Logger.getLogger(ICUData.class.getName()) : null;

    public static boolean exists(final String resourceName) {
        URL i = null;
        if (System.getSecurityManager() != null) {
            i = AccessController.doPrivileged(new PrivilegedAction<URL>() {
                    public URL run() {
                        return ICUData.class.getResource(resourceName);
                    }
                });
        } else {
            i = ICUData.class.getResource(resourceName);
        }
        return i != null;
    }

    private static InputStream getStream(final Class<?> root, final String resourceName, boolean required) {
        InputStream i = null;
        if (System.getSecurityManager() != null) {
            i = AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
                    public InputStream run() {
                        return root.getResourceAsStream(resourceName);
                    }
                });
        } else {
            i = root.getResourceAsStream(resourceName);
        }

        if (i == null && required) {
            throw new MissingResourceException("could not locate data " +resourceName, root.getPackage().getName(), resourceName);
        }
        checkStreamForBinaryData(i, resourceName);
        return i;
    }

    /**
     * Should be called only from ICUBinary.getData() or from convenience overloads here.
     */
    static InputStream getStream(final ClassLoader loader, final String resourceName, boolean required) {
        InputStream i = null;
        if (System.getSecurityManager() != null) {
            i = AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
                    public InputStream run() {
                        return loader.getResourceAsStream(resourceName);
                    }
                });
        } else {
            i = loader.getResourceAsStream(resourceName);
        }
        if (i == null && required) {
            throw new MissingResourceException("could not locate data", loader.toString(), resourceName);
        }
        checkStreamForBinaryData(i, resourceName);
        return i;
    }

    @SuppressWarnings("unused")  // used if logBinaryDataFromInputStream == true
    private static void checkStreamForBinaryData(InputStream is, String resourceName) {
        if (logBinaryDataFromInputStream && is != null && resourceName.indexOf(PACKAGE_NAME) >= 0) {
            try {
                is.mark(32);
                byte[] b = new byte[32];
                int len = is.read(b);
                if (len == 32 && b[2] == (byte)0xda && b[3] == 0x27) {
                    String msg = String.format(
                            "ICU binary data file loaded from Class/ClassLoader as InputStream " +
                            "from %s: MappedData %02x%02x%02x%02x  dataFormat %02x%02x%02x%02x",
                            resourceName,
                            b[0], b[1], b[2], b[3],
                            b[12], b[13], b[14], b[15]);
                    logger.info(msg);
                }
                is.reset();
            } catch (IOException ignored) {
            }
        }
    }

    public static InputStream getStream(ClassLoader loader, String resourceName){
        return getStream(loader,resourceName, false);
    }

    public static InputStream getRequiredStream(ClassLoader loader, String resourceName){
        return getStream(loader, resourceName, true);
    }

    /**
     * Convenience override that calls getStream(ICUData.class, resourceName, false);
     * Returns null if the resource could not be found.
     */
    public static InputStream getStream(String resourceName) {
        return getStream(ICUData.class, resourceName, false);
    }

    /**
     * Convenience method that calls getStream(ICUData.class, resourceName, true).
     * @throws MissingResourceException if the resource could not be found
     */
    public static InputStream getRequiredStream(String resourceName) {
        return getStream(ICUData.class, resourceName, true);
    }

    /**
     * Convenience override that calls getStream(root, resourceName, false);
     * Returns null if the resource could not be found.
     */
    public static InputStream getStream(Class<?> root, String resourceName) {
        return getStream(root, resourceName, false);
    }

    /**
     * Convenience method that calls getStream(root, resourceName, true).
     * @throws MissingResourceException if the resource could not be found
     */
    public static InputStream getRequiredStream(Class<?> root, String resourceName) {
        return getStream(root, resourceName, true);
    }
}