blob: ab43d1b32dce21e2e456a578bd03b74014414bc5 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2004-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
* Created on Feb 4, 2004
*
*/
package com.ibm.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 com.ibm.icu.util.VersionInfo;
/**
* Provides access to ICU data files as InputStreams. Implements security checking.
*/
public final class ICUData {
/**
* The data path to be used with getBundleInstance API
*/
static final String ICU_DATA_PATH = "com/ibm/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);
}
}