ICU-10940 make ICUResourceBundleImpl smaller, remove lookup cache in favor of newer Reader cache, reduce object creation while finding resources and especially strings with fallback
X-SVN-Rev: 35936
This commit is contained in:
parent
30dc6d9bbb
commit
df08e453dc
@ -85,12 +85,8 @@ public final class CollationLoader {
|
|||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final UResourceBundle getWithFallback(UResourceBundle table, String entryName) {
|
private static final UResourceBundle findWithFallback(UResourceBundle table, String entryName) {
|
||||||
try {
|
return ((ICUResourceBundle)table).findWithFallback(entryName);
|
||||||
return ((ICUResourceBundle)table).getWithFallback(entryName);
|
|
||||||
} catch(MissingResourceException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CollationTailoring loadTailoring(ULocale locale, Output<ULocale> outValidLocale) {
|
public static CollationTailoring loadTailoring(ULocale locale, Output<ULocale> outValidLocale) {
|
||||||
@ -127,7 +123,7 @@ public final class CollationLoader {
|
|||||||
// There are zero or more tailorings in the collations table.
|
// There are zero or more tailorings in the collations table.
|
||||||
UResourceBundle collations;
|
UResourceBundle collations;
|
||||||
try {
|
try {
|
||||||
collations = ((ICUResourceBundle)bundle).get("collations");
|
collations = bundle.get("collations");
|
||||||
if (collations == null) {
|
if (collations == null) {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
@ -139,12 +135,9 @@ public final class CollationLoader {
|
|||||||
String type = locale.getKeywordValue("collation");
|
String type = locale.getKeywordValue("collation");
|
||||||
String defaultType = "standard";
|
String defaultType = "standard";
|
||||||
|
|
||||||
try {
|
String defT = ((ICUResourceBundle)collations).findStringWithFallback("default");
|
||||||
String defT = ((ICUResourceBundle)collations).getStringWithFallback("default");
|
if (defT != null) {
|
||||||
if (defT != null) {
|
defaultType = defT;
|
||||||
defaultType = defT;
|
|
||||||
}
|
|
||||||
} catch(MissingResourceException ignored) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == null || type.equals("default")) {
|
if (type == null || type.equals("default")) {
|
||||||
@ -159,27 +152,27 @@ public final class CollationLoader {
|
|||||||
// ICU4C, but not used by ICU4J
|
// ICU4C, but not used by ICU4J
|
||||||
|
|
||||||
// boolean typeFallback = false;
|
// boolean typeFallback = false;
|
||||||
UResourceBundle data = getWithFallback(collations, type);
|
UResourceBundle data = findWithFallback(collations, type);
|
||||||
if (data == null &&
|
if (data == null &&
|
||||||
type.length() > 6 && type.startsWith("search")) {
|
type.length() > 6 && type.startsWith("search")) {
|
||||||
// fall back from something like "searchjl" to "search"
|
// fall back from something like "searchjl" to "search"
|
||||||
// typeFallback = true;
|
// typeFallback = true;
|
||||||
type = "search";
|
type = "search";
|
||||||
data = getWithFallback(collations, type);
|
data = findWithFallback(collations, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data == null && !type.equals(defaultType)) {
|
if (data == null && !type.equals(defaultType)) {
|
||||||
// fall back to the default type
|
// fall back to the default type
|
||||||
// typeFallback = true;
|
// typeFallback = true;
|
||||||
type = defaultType;
|
type = defaultType;
|
||||||
data = getWithFallback(collations, type);
|
data = findWithFallback(collations, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data == null && !type.equals("standard")) {
|
if (data == null && !type.equals("standard")) {
|
||||||
// fall back to the "standard" type
|
// fall back to the "standard" type
|
||||||
// typeFallback = true;
|
// typeFallback = true;
|
||||||
type = "standard";
|
type = "standard";
|
||||||
data = getWithFallback(collations, type);
|
data = findWithFallback(collations, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
@ -213,7 +206,7 @@ public final class CollationLoader {
|
|||||||
|
|
||||||
// Try to fetch the optional rules string.
|
// Try to fetch the optional rules string.
|
||||||
try {
|
try {
|
||||||
String s = ((ICUResourceBundle)data).getString("Sequence");
|
String s = data.getString("Sequence");
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
t.rules = s;
|
t.rules = s;
|
||||||
}
|
}
|
||||||
@ -236,12 +229,9 @@ public final class CollationLoader {
|
|||||||
// Opening a bundle for the actual locale should always succeed.
|
// Opening a bundle for the actual locale should always succeed.
|
||||||
UResourceBundle actualBundle = UResourceBundle.getBundleInstance(
|
UResourceBundle actualBundle = UResourceBundle.getBundleInstance(
|
||||||
ICUResourceBundle.ICU_COLLATION_BASE_NAME, actualLocale);
|
ICUResourceBundle.ICU_COLLATION_BASE_NAME, actualLocale);
|
||||||
try {
|
defT = ((ICUResourceBundle)actualBundle).findStringWithFallback("collations/default");
|
||||||
String defT = ((ICUResourceBundle)actualBundle).getStringWithFallback("collations/default");
|
if (defT != null) {
|
||||||
if (defT != null) {
|
defaultType = defT;
|
||||||
defaultType = defT;
|
|
||||||
}
|
|
||||||
} catch(MissingResourceException ignored) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* *****************************************************************************
|
* *****************************************************************************
|
||||||
* Copyright (C) 2005-2014, International Business Machines Corporation and *
|
* Copyright (C) 2005-2014, International Business Machines Corporation and
|
||||||
* others. All Rights Reserved. *
|
* others. All Rights Reserved.
|
||||||
* *****************************************************************************
|
* *****************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -23,13 +23,12 @@ import java.util.Locale;
|
|||||||
import java.util.MissingResourceException;
|
import java.util.MissingResourceException;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
import com.ibm.icu.impl.URLHandler.URLVisitor;
|
import com.ibm.icu.impl.URLHandler.URLVisitor;
|
||||||
import com.ibm.icu.util.Output;
|
|
||||||
import com.ibm.icu.util.ULocale;
|
import com.ibm.icu.util.ULocale;
|
||||||
import com.ibm.icu.util.UResourceBundle;
|
import com.ibm.icu.util.UResourceBundle;
|
||||||
import com.ibm.icu.util.UResourceBundleIterator;
|
import com.ibm.icu.util.UResourceBundleIterator;
|
||||||
|
import com.ibm.icu.util.UResourceTypeMismatchException;
|
||||||
import com.ibm.icu.util.VersionInfo;
|
import com.ibm.icu.util.VersionInfo;
|
||||||
|
|
||||||
public class ICUResourceBundle extends UResourceBundle {
|
public class ICUResourceBundle extends UResourceBundle {
|
||||||
@ -79,11 +78,6 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
|
|
||||||
private static final String NO_INHERITANCE_MARKER = "\u2205\u2205\u2205";
|
private static final String NO_INHERITANCE_MARKER = "\u2205\u2205\u2205";
|
||||||
|
|
||||||
/**
|
|
||||||
* The actual path of the resource
|
|
||||||
*/
|
|
||||||
protected String resPath;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class loader constant to be used with getBundleInstance API
|
* The class loader constant to be used with getBundleInstance API
|
||||||
*/
|
*/
|
||||||
@ -131,13 +125,37 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the respath of this bundle
|
* Fields for a whole bundle, rather than any specific resource in the bundle.
|
||||||
* @return the respath of the bundle
|
* Corresponds roughly to ICU4C/source/common/uresimp.h struct UResourceDataEntry.
|
||||||
*/
|
*/
|
||||||
public String getResPath(){
|
protected static final class WholeBundle {
|
||||||
return resPath;
|
WholeBundle(String baseName, String localeID, ClassLoader loader,
|
||||||
|
ICUResourceBundleReader reader) {
|
||||||
|
this.baseName = baseName;
|
||||||
|
this.localeID = localeID;
|
||||||
|
this.ulocale = new ULocale(localeID);
|
||||||
|
this.loader = loader;
|
||||||
|
this.reader = reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
String baseName;
|
||||||
|
String localeID;
|
||||||
|
ULocale ulocale;
|
||||||
|
ClassLoader loader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access to the bits and bytes of the resource bundle.
|
||||||
|
* Hides low-level details.
|
||||||
|
*/
|
||||||
|
ICUResourceBundleReader reader;
|
||||||
|
|
||||||
|
// TODO: Remove topLevelKeys when we upgrade to Java 6 where ResourceBundle caches the keySet().
|
||||||
|
Set<String> topLevelKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WholeBundle wholeBundle;
|
||||||
|
private ICUResourceBundle container;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a functionally equivalent locale, considering keywords as well, for the specified keyword.
|
* Returns a functionally equivalent locale, considering keywords as well, for the specified keyword.
|
||||||
* @param baseName resource specifier
|
* @param baseName resource specifier
|
||||||
@ -339,7 +357,7 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
ICUResourceBundle actualBundle = this;
|
ICUResourceBundle actualBundle = this;
|
||||||
|
|
||||||
// now recurse to pick up sub levels of the items
|
// now recurse to pick up sub levels of the items
|
||||||
ICUResourceBundle result = findResourceWithFallback(path, actualBundle, null, null);
|
ICUResourceBundle result = findResourceWithFallback(path, actualBundle, null);
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new MissingResourceException(
|
throw new MissingResourceException(
|
||||||
@ -384,21 +402,17 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
* @return the resource, or null
|
* @return the resource, or null
|
||||||
*/
|
*/
|
||||||
public ICUResourceBundle findWithFallback(String path) {
|
public ICUResourceBundle findWithFallback(String path) {
|
||||||
return findResourceWithFallback(path, this, null, null);
|
return findResourceWithFallback(path, this, null);
|
||||||
}
|
}
|
||||||
public String findStringWithFallback(String path) {
|
public String findStringWithFallback(String path) {
|
||||||
Output<String> outString = new Output<String>();
|
return findStringWithFallback(path, this, null);
|
||||||
findResourceWithFallback(path, this, null, outString);
|
|
||||||
return outString.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// will throw type mismatch exception if the resource is not a string
|
// will throw type mismatch exception if the resource is not a string
|
||||||
public String getStringWithFallback(String path) throws MissingResourceException {
|
public String getStringWithFallback(String path) throws MissingResourceException {
|
||||||
// Optimized form of getWithFallback(path).getString();
|
// Optimized form of getWithFallback(path).getString();
|
||||||
ICUResourceBundle actualBundle = this;
|
ICUResourceBundle actualBundle = this;
|
||||||
Output<String> outString = new Output<String>();
|
String result = findStringWithFallback(path, actualBundle, null);
|
||||||
findResourceWithFallback(path, actualBundle, null, outString);
|
|
||||||
String result = outString.value;
|
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
throw new MissingResourceException(
|
throw new MissingResourceException(
|
||||||
@ -796,64 +810,229 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
return GET_AVAILABLE_CACHE.getInstance(key, loader);
|
return GET_AVAILABLE_CACHE.getInstance(key, loader);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final ICUResourceBundle findResourceWithFallback(String path,
|
private static final ICUResourceBundle findResourceWithFallback(String path,
|
||||||
UResourceBundle actualBundle, UResourceBundle requested,
|
UResourceBundle actualBundle, UResourceBundle requested) {
|
||||||
Output<String> outString) {
|
if (path.length() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
ICUResourceBundle sub = null;
|
ICUResourceBundle sub = null;
|
||||||
if (requested == null) {
|
if (requested == null) {
|
||||||
requested = actualBundle;
|
requested = actualBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
ICUResourceBundle base = (ICUResourceBundle) actualBundle;
|
ICUResourceBundle base = (ICUResourceBundle) actualBundle;
|
||||||
String basePath = ((ICUResourceBundle)actualBundle).resPath.length() > 0 ?
|
// Collect existing and parsed key objects into an array of keys,
|
||||||
((ICUResourceBundle)actualBundle).resPath : "";
|
// rather than assembling and parsing paths.
|
||||||
|
int depth = base.getResDepth();
|
||||||
|
int numPathKeys = countPathKeys(path);
|
||||||
|
assert numPathKeys > 0;
|
||||||
|
String[] keys = new String[depth + numPathKeys];
|
||||||
|
getResPathKeys(path, numPathKeys, keys, depth);
|
||||||
|
|
||||||
while (base != null) {
|
for (;;) { // Iterate over the parent bundles.
|
||||||
if (path.indexOf('/') == -1) { // skip the tokenizer
|
for (;;) { // Iterate over the keys on the requested path, within a bundle.
|
||||||
if (outString != null && base instanceof ICUResourceBundleImpl.ResourceTable) {
|
String subKey = keys[depth++];
|
||||||
String s = ((ICUResourceBundleImpl.ResourceTable)base).getStringOrNull(path);
|
sub = (ICUResourceBundle) base.handleGet(subKey, null, requested);
|
||||||
if (s != null) {
|
if (sub == null) {
|
||||||
outString.value = s;
|
--depth;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sub = (ICUResourceBundle) base.handleGet(path, null, requested);
|
|
||||||
if (sub != null) {
|
|
||||||
if (outString != null && sub.getType() == STRING) {
|
|
||||||
outString.value = sub.getString(); // string from alias handling
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
if (depth == keys.length) {
|
||||||
ICUResourceBundle currentBase = base;
|
// We found it.
|
||||||
StringTokenizer st = new StringTokenizer(path, "/");
|
sub.setLoadingStatus(((ICUResourceBundle)requested).getLocaleID());
|
||||||
while (st.hasMoreTokens()) {
|
return sub;
|
||||||
String subKey = st.nextToken();
|
}
|
||||||
sub = ICUResourceBundle.findResourceWithFallback(subKey, currentBase, requested,
|
base = sub;
|
||||||
st.hasMoreTokens() ? null : outString);
|
}
|
||||||
if (sub == null) {
|
// Try the parent bundle of the last-found resource.
|
||||||
if (outString != null && outString.value != null) {
|
ICUResourceBundle nextBase = (ICUResourceBundle)base.getParent();
|
||||||
return null;
|
if (nextBase == null) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
// If we followed an alias, then we may have switched bundle (locale) and key path.
|
||||||
|
// Set the lower parts of the path according to the last-found resource.
|
||||||
|
// This relies on a resource found via alias to have its original location information,
|
||||||
|
// rather than the location of the alias.
|
||||||
|
int baseDepth = base.getResDepth();
|
||||||
|
if (depth != baseDepth) {
|
||||||
|
String[] newKeys = new String[baseDepth + (keys.length - depth)];
|
||||||
|
System.arraycopy(keys, depth, newKeys, baseDepth, keys.length - depth);
|
||||||
|
keys = newKeys;
|
||||||
|
}
|
||||||
|
base.getResPathKeys(keys, baseDepth);
|
||||||
|
base = nextBase;
|
||||||
|
depth = 0; // getParent() returned a top level table resource.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like findResourceWithFallback(...).getString() but with minimal creation of intermediate
|
||||||
|
* ICUResourceBundle objects.
|
||||||
|
*/
|
||||||
|
private static final String findStringWithFallback(String path,
|
||||||
|
UResourceBundle actualBundle, UResourceBundle requested) {
|
||||||
|
if (path.length() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!(actualBundle instanceof ICUResourceBundleImpl.ResourceContainer)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (requested == null) {
|
||||||
|
requested = actualBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICUResourceBundle base = (ICUResourceBundle) actualBundle;
|
||||||
|
ICUResourceBundleReader reader = base.wholeBundle.reader;
|
||||||
|
int res = RES_BOGUS;
|
||||||
|
|
||||||
|
// Collect existing and parsed key objects into an array of keys,
|
||||||
|
// rather than assembling and parsing paths.
|
||||||
|
int baseDepth = base.getResDepth();
|
||||||
|
int depth = baseDepth;
|
||||||
|
int numPathKeys = countPathKeys(path);
|
||||||
|
assert numPathKeys > 0;
|
||||||
|
String[] keys = new String[depth + numPathKeys];
|
||||||
|
getResPathKeys(path, numPathKeys, keys, depth);
|
||||||
|
|
||||||
|
for (;;) { // Iterate over the parent bundles.
|
||||||
|
for (;;) { // Iterate over the keys on the requested path, within a bundle.
|
||||||
|
ICUResourceBundleReader.Container readerContainer;
|
||||||
|
if (res == RES_BOGUS) {
|
||||||
|
int type = base.getType();
|
||||||
|
if (type == TABLE || type == ARRAY) {
|
||||||
|
readerContainer = ((ICUResourceBundleImpl.ResourceContainer)base).value;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int type = ICUResourceBundleReader.RES_GET_TYPE(res);
|
||||||
|
if (ICUResourceBundleReader.URES_IS_TABLE(type)) {
|
||||||
|
readerContainer = reader.getTable(res);
|
||||||
|
} else if (ICUResourceBundleReader.URES_IS_ARRAY(type)) {
|
||||||
|
readerContainer = reader.getArray(res);
|
||||||
|
} else {
|
||||||
|
res = RES_BOGUS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
currentBase = sub;
|
|
||||||
}
|
}
|
||||||
if (sub != null) {
|
String subKey = keys[depth++];
|
||||||
//we found it
|
res = readerContainer.getResource(reader, subKey);
|
||||||
|
if (res == RES_BOGUS) {
|
||||||
|
--depth;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
ICUResourceBundle sub;
|
||||||
|
if (ICUResourceBundleReader.RES_GET_TYPE(res) == ALIAS) {
|
||||||
|
base.getResPathKeys(keys, baseDepth);
|
||||||
|
sub = getAliasedResource(base, keys, depth, subKey, res, null, requested);
|
||||||
|
} else {
|
||||||
|
sub = null;
|
||||||
|
}
|
||||||
|
if (depth == keys.length) {
|
||||||
|
// We found it.
|
||||||
|
if (sub != null) {
|
||||||
|
return sub.getString(); // string from alias handling
|
||||||
|
} else {
|
||||||
|
String s = reader.getString(res);
|
||||||
|
if (s == null) {
|
||||||
|
throw new UResourceTypeMismatchException("");
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sub != null) {
|
||||||
|
base = sub;
|
||||||
|
reader = base.wholeBundle.reader;
|
||||||
|
res = RES_BOGUS;
|
||||||
|
// If we followed an alias, then we may have switched bundle (locale) and key path.
|
||||||
|
// Reserve space for the lower parts of the path according to the last-found resource.
|
||||||
|
// This relies on a resource found via alias to have its original location information,
|
||||||
|
// rather than the location of the alias.
|
||||||
|
baseDepth = base.getResDepth();
|
||||||
|
if (depth != baseDepth) {
|
||||||
|
String[] newKeys = new String[baseDepth + (keys.length - depth)];
|
||||||
|
System.arraycopy(keys, depth, newKeys, baseDepth, keys.length - depth);
|
||||||
|
keys = newKeys;
|
||||||
|
depth = baseDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// if not try the parent bundle - note, getParent() returns the bundle root
|
// Try the parent bundle of the last-found resource.
|
||||||
base = (ICUResourceBundle)base.getParent();
|
ICUResourceBundle nextBase = (ICUResourceBundle)base.getParent();
|
||||||
path = basePath.length() > 0 ? basePath + "/" + path : path;
|
if (nextBase == null) {
|
||||||
basePath = "";
|
return null;
|
||||||
|
}
|
||||||
|
// We probably have not yet set the lower parts of the key path.
|
||||||
|
base.getResPathKeys(keys, baseDepth);
|
||||||
|
base = nextBase;
|
||||||
|
reader = base.wholeBundle.reader;
|
||||||
|
depth = baseDepth = 0; // getParent() returned a top level table resource.
|
||||||
}
|
}
|
||||||
if(sub != null){
|
}
|
||||||
sub.setLoadingStatus(((ICUResourceBundle)requested).getLocaleID());
|
|
||||||
|
private int getResDepth() {
|
||||||
|
return (container == null) ? 0 : container.getResDepth() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills some of the keys array with the keys on the path to this resource object.
|
||||||
|
* Writes the top-level key into index 0 and increments from there.
|
||||||
|
*
|
||||||
|
* @param keys
|
||||||
|
* @param depth must be {@link #getResDepth()}
|
||||||
|
*/
|
||||||
|
private void getResPathKeys(String[] keys, int depth) {
|
||||||
|
ICUResourceBundle b = this;
|
||||||
|
while (depth > 0) {
|
||||||
|
keys[--depth] = b.key;
|
||||||
|
b = b.container;
|
||||||
|
assert (depth == 0) == (b.container == null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countPathKeys(String path) {
|
||||||
|
if (path.length() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int num = 1;
|
||||||
|
for (int i = 0; i < path.length(); ++i) {
|
||||||
|
if (path.charAt(i) == RES_PATH_SEP_CHAR) {
|
||||||
|
++num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills some of the keys array (from start) with the num keys from the path string.
|
||||||
|
*
|
||||||
|
* @param path path string
|
||||||
|
* @param num must be {@link #countPathKeys(String)}
|
||||||
|
* @param keys
|
||||||
|
* @param start index where the first path key is stored
|
||||||
|
*/
|
||||||
|
private static void getResPathKeys(String path, int num, String[] keys, int start) {
|
||||||
|
if (num == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (num == 1) {
|
||||||
|
keys[start] = path;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
for (;;) {
|
||||||
|
int j = path.indexOf(RES_PATH_SEP_CHAR, i);
|
||||||
|
assert j >= i;
|
||||||
|
keys[start++] = path.substring(i, j);
|
||||||
|
if (num == 2) {
|
||||||
|
assert path.indexOf(RES_PATH_SEP_CHAR, j + 1) < 0;
|
||||||
|
keys[start] = path.substring(j + 1);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
i = j + 1;
|
||||||
|
--num;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sub;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
@ -884,7 +1063,7 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
// recursively build bundle .. over-ride super class method.
|
// recursively build bundle
|
||||||
protected synchronized static UResourceBundle instantiateBundle(String baseName, String localeID,
|
protected synchronized static UResourceBundle instantiateBundle(String baseName, String localeID,
|
||||||
ClassLoader root, boolean disableFallback){
|
ClassLoader root, boolean disableFallback){
|
||||||
ULocale defaultLocale = ULocale.getDefault();
|
ULocale defaultLocale = ULocale.getDefault();
|
||||||
@ -947,8 +1126,8 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
|
|
||||||
b = (ICUResourceBundle)addToCache(root, fullName, defaultLocale, b);
|
b = (ICUResourceBundle)addToCache(root, fullName, defaultLocale, b);
|
||||||
|
|
||||||
if (b.getTableResource("%%Parent") != RES_BOGUS) {
|
String parentLocaleName = ((ICUResourceBundleImpl.ResourceTable)b).findString("%%Parent");
|
||||||
String parentLocaleName = b.getString("%%Parent");
|
if (parentLocaleName != null) {
|
||||||
parent = instantiateBundle(baseName, parentLocaleName, root, disableFallback);
|
parent = instantiateBundle(baseName, parentLocaleName, root, disableFallback);
|
||||||
} else if (i != -1) {
|
} else if (i != -1) {
|
||||||
parent = instantiateBundle(baseName, localeName.substring(0, i), root, disableFallback);
|
parent = instantiateBundle(baseName, localeName.substring(0, i), root, disableFallback);
|
||||||
@ -963,13 +1142,13 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
UResourceBundle get(String aKey, HashMap<String, String> table, UResourceBundle requested) {
|
UResourceBundle get(String aKey, HashMap<String, String> aliasesVisited, UResourceBundle requested) {
|
||||||
ICUResourceBundle obj = (ICUResourceBundle)handleGet(aKey, table, requested);
|
ICUResourceBundle obj = (ICUResourceBundle)handleGet(aKey, aliasesVisited, requested);
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
obj = (ICUResourceBundle)getParent();
|
obj = (ICUResourceBundle)getParent();
|
||||||
if (obj != null) {
|
if (obj != null) {
|
||||||
//call the get method to recursively fetch the resource
|
//call the get method to recursively fetch the resource
|
||||||
obj = (ICUResourceBundle)obj.get(aKey, table, requested);
|
obj = (ICUResourceBundle)obj.get(aKey, aliasesVisited, requested);
|
||||||
}
|
}
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
String fullName = ICUResourceBundleReader.getFullName(getBaseName(), getLocaleID());
|
String fullName = ICUResourceBundleReader.getFullName(getBaseName(), getLocaleID());
|
||||||
@ -982,20 +1161,8 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String localeID;
|
|
||||||
protected String baseName;
|
|
||||||
protected ULocale ulocale;
|
|
||||||
protected ClassLoader loader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access to the bits and bytes of the resource bundle.
|
|
||||||
* Hides low-level details.
|
|
||||||
*/
|
|
||||||
protected ICUResourceBundleReader reader;
|
|
||||||
/** Data member where the subclasses store the key. */
|
/** Data member where the subclasses store the key. */
|
||||||
protected String key;
|
protected String key;
|
||||||
/** Data member where the subclasses store the offset within resource data. */
|
|
||||||
protected int resource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A resource word value that means "no resource".
|
* A resource word value that means "no resource".
|
||||||
@ -1050,15 +1217,15 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String getLocaleID() {
|
protected String getLocaleID() {
|
||||||
return localeID;
|
return wholeBundle.localeID;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getBaseName() {
|
protected String getBaseName() {
|
||||||
return baseName;
|
return wholeBundle.baseName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ULocale getULocale() {
|
public ULocale getULocale() {
|
||||||
return ulocale;
|
return wholeBundle.ulocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UResourceBundle getParent() {
|
public UResourceBundle getParent() {
|
||||||
@ -1073,113 +1240,96 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int[] gPublicTypes = new int[] {
|
|
||||||
STRING,
|
|
||||||
BINARY,
|
|
||||||
TABLE,
|
|
||||||
ALIAS,
|
|
||||||
|
|
||||||
TABLE, /* TABLE32 */
|
|
||||||
TABLE, /* TABLE16 */
|
|
||||||
STRING, /* STRING_V2 */
|
|
||||||
INT,
|
|
||||||
|
|
||||||
ARRAY,
|
|
||||||
ARRAY, /* ARRAY16 */
|
|
||||||
NONE,
|
|
||||||
NONE,
|
|
||||||
|
|
||||||
NONE,
|
|
||||||
NONE,
|
|
||||||
INT_VECTOR,
|
|
||||||
NONE
|
|
||||||
};
|
|
||||||
|
|
||||||
public int getType() {
|
|
||||||
return gPublicTypes[ICUResourceBundleReader.RES_GET_TYPE(resource)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the noFallback flag specified in the loaded bundle.
|
* Get the noFallback flag specified in the loaded bundle.
|
||||||
* @return The noFallback flag.
|
* @return The noFallback flag.
|
||||||
*/
|
*/
|
||||||
private boolean getNoFallback() {
|
private boolean getNoFallback() {
|
||||||
return reader.getNoFallback();
|
return wholeBundle.reader.getNoFallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ICUResourceBundle getBundle(ICUResourceBundleReader reader,
|
private static ICUResourceBundle getBundle(ICUResourceBundleReader reader,
|
||||||
String baseName, String localeID,
|
String baseName, String localeID,
|
||||||
ClassLoader loader) {
|
ClassLoader loader) {
|
||||||
ICUResourceBundleImpl bundle;
|
ICUResourceBundleImpl.ResourceTable rootTable;
|
||||||
int rootRes = reader.getRootResource();
|
int rootRes = reader.getRootResource();
|
||||||
if(gPublicTypes[ICUResourceBundleReader.RES_GET_TYPE(rootRes)] == TABLE) {
|
if(ICUResourceBundleReader.URES_IS_TABLE(ICUResourceBundleReader.RES_GET_TYPE(rootRes))) {
|
||||||
bundle = new ICUResourceBundleImpl.ResourceTable(reader, null, "", rootRes, null);
|
WholeBundle wb = new WholeBundle(baseName, localeID, loader, reader);
|
||||||
|
rootTable = new ICUResourceBundleImpl.ResourceTable(wb, rootRes);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Invalid format error");
|
throw new IllegalStateException("Invalid format error");
|
||||||
}
|
}
|
||||||
bundle.baseName = baseName;
|
String aliasString = rootTable.findString("%%ALIAS");
|
||||||
bundle.localeID = localeID;
|
if(aliasString != null) {
|
||||||
bundle.ulocale = new ULocale(localeID);
|
return (ICUResourceBundle)UResourceBundle.getBundleInstance(baseName, aliasString);
|
||||||
bundle.loader = loader;
|
|
||||||
UResourceBundle alias = bundle.handleGetImpl("%%ALIAS", null, bundle, null, null); // handleGet will cache the bundle with no parent set
|
|
||||||
if(alias != null) {
|
|
||||||
return (ICUResourceBundle)UResourceBundle.getBundleInstance(baseName, alias.getString());
|
|
||||||
} else {
|
} else {
|
||||||
return bundle;
|
return rootTable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Constructor for the root table of a bundle.
|
||||||
|
*/
|
||||||
|
protected ICUResourceBundle(WholeBundle wholeBundle) {
|
||||||
|
this.wholeBundle = wholeBundle;
|
||||||
|
}
|
||||||
// constructor for inner classes
|
// constructor for inner classes
|
||||||
protected ICUResourceBundle(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
protected ICUResourceBundle(ICUResourceBundle container, String key) {
|
||||||
ICUResourceBundle container) {
|
|
||||||
this.reader = reader;
|
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.resPath = resPath;
|
wholeBundle = container.wholeBundle;
|
||||||
this.resource = resource;
|
this.container = (ICUResourceBundleImpl.ResourceContainer) container;
|
||||||
if(container != null) {
|
parent = container.parent;
|
||||||
baseName = container.baseName;
|
|
||||||
localeID = container.localeID;
|
|
||||||
ulocale = container.ulocale;
|
|
||||||
loader = container.loader;
|
|
||||||
this.parent = container.parent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAliasValue(int res) {
|
|
||||||
String result = reader.getAlias(res);
|
|
||||||
return result != null ? result : "";
|
|
||||||
}
|
|
||||||
private static final char RES_PATH_SEP_CHAR = '/';
|
private static final char RES_PATH_SEP_CHAR = '/';
|
||||||
private static final String RES_PATH_SEP_STR = "/";
|
private static final String RES_PATH_SEP_STR = "/";
|
||||||
private static final String ICUDATA = "ICUDATA";
|
private static final String ICUDATA = "ICUDATA";
|
||||||
private static final char HYPHEN = '-';
|
private static final char HYPHEN = '-';
|
||||||
private static final String LOCALE = "LOCALE";
|
private static final String LOCALE = "LOCALE";
|
||||||
|
|
||||||
protected ICUResourceBundle findResource(String key,
|
/**
|
||||||
String resPath,
|
* Returns the resource object referred to from the alias _resource int's path string.
|
||||||
int _resource,
|
* Throws MissingResourceException if not found.
|
||||||
HashMap<String, String> table,
|
*
|
||||||
UResourceBundle requested) {
|
* If the alias path does not contain a key path:
|
||||||
ClassLoader loaderToUse = loader;
|
* If keys != null then keys[:depth] is used.
|
||||||
|
* Otherwise the base key path plus the key parameter is used.
|
||||||
|
*
|
||||||
|
* @param base A direct or indirect container of the alias.
|
||||||
|
* @param keys The key path to the alias, or null. (const)
|
||||||
|
* @param depth The length of the key path, if keys != null.
|
||||||
|
* @param key The alias' own key within this current container, if keys == null.
|
||||||
|
* @param _resource The alias resource int.
|
||||||
|
* @param aliasesVisited Set of alias path strings already visited, for detecting loops.
|
||||||
|
* We cannot change the type (e.g., to Set<String>) because it is used
|
||||||
|
* in protected/@stable UResourceBundle methods.
|
||||||
|
* @param requested The original resource object from which the lookup started,
|
||||||
|
* which is the starting point for "/LOCALE/..." aliases.
|
||||||
|
* @return the aliased resource object
|
||||||
|
*/
|
||||||
|
protected static ICUResourceBundle getAliasedResource(
|
||||||
|
ICUResourceBundle base, String[] keys, int depth,
|
||||||
|
String key, int _resource,
|
||||||
|
HashMap<String, String> aliasesVisited,
|
||||||
|
UResourceBundle requested) {
|
||||||
|
WholeBundle wholeBundle = base.wholeBundle;
|
||||||
|
ClassLoader loaderToUse = wholeBundle.loader;
|
||||||
String locale = null, keyPath = null;
|
String locale = null, keyPath = null;
|
||||||
String bundleName;
|
String bundleName;
|
||||||
String rpath = getAliasValue(_resource);
|
String rpath = wholeBundle.reader.getAlias(_resource);
|
||||||
if (table == null) {
|
if (aliasesVisited == null) {
|
||||||
table = new HashMap<String, String>();
|
aliasesVisited = new HashMap<String, String>();
|
||||||
}
|
}
|
||||||
if (table.get(rpath) != null) {
|
if (aliasesVisited.get(rpath) != null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Circular references in the resource bundles");
|
"Circular references in the resource bundles");
|
||||||
}
|
}
|
||||||
table.put(rpath, "");
|
aliasesVisited.put(rpath, "");
|
||||||
if (rpath.indexOf(RES_PATH_SEP_CHAR) == 0) {
|
if (rpath.indexOf(RES_PATH_SEP_CHAR) == 0) {
|
||||||
int i = rpath.indexOf(RES_PATH_SEP_CHAR, 1);
|
int i = rpath.indexOf(RES_PATH_SEP_CHAR, 1);
|
||||||
int j = rpath.indexOf(RES_PATH_SEP_CHAR, i + 1);
|
int j = rpath.indexOf(RES_PATH_SEP_CHAR, i + 1);
|
||||||
bundleName = rpath.substring(1, i);
|
bundleName = rpath.substring(1, i);
|
||||||
if (j < 0) {
|
if (j < 0) {
|
||||||
locale = rpath.substring(i + 1);
|
locale = rpath.substring(i + 1);
|
||||||
// if key path is not available,
|
|
||||||
// use the given key path
|
|
||||||
keyPath = resPath;
|
|
||||||
} else {
|
} else {
|
||||||
locale = rpath.substring(i + 1, j);
|
locale = rpath.substring(i + 1, j);
|
||||||
keyPath = rpath.substring(j + 1, rpath.length());
|
keyPath = rpath.substring(j + 1, rpath.length());
|
||||||
@ -1203,34 +1353,21 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
keyPath = rpath.substring(i + 1);
|
keyPath = rpath.substring(i + 1);
|
||||||
} else {
|
} else {
|
||||||
locale = rpath;
|
locale = rpath;
|
||||||
// if key path is not available,
|
|
||||||
// use the given key path
|
|
||||||
keyPath = resPath;
|
|
||||||
}
|
}
|
||||||
bundleName = baseName;
|
bundleName = wholeBundle.baseName;
|
||||||
}
|
}
|
||||||
ICUResourceBundle bundle = null;
|
ICUResourceBundle bundle = null;
|
||||||
ICUResourceBundle sub = null;
|
ICUResourceBundle sub = null;
|
||||||
if(bundleName.equals(LOCALE)){
|
if(bundleName.equals(LOCALE)){
|
||||||
bundleName = baseName;
|
bundleName = wholeBundle.baseName;
|
||||||
keyPath = rpath.substring(LOCALE.length() + 2/* prepending and appending / */, rpath.length());
|
keyPath = rpath.substring(LOCALE.length() + 2/* prepending and appending / */, rpath.length());
|
||||||
locale = ((ICUResourceBundle)requested).getLocaleID();
|
|
||||||
|
|
||||||
// Get the top bundle of the requested bundle
|
// Get the top bundle of the requested bundle
|
||||||
bundle = (ICUResourceBundle)getBundleInstance(bundleName, locale, loaderToUse, false);
|
bundle = (ICUResourceBundle)requested;
|
||||||
if (bundle != null) {
|
while (bundle.container != null) {
|
||||||
sub = ICUResourceBundle.findResourceWithFallback(keyPath, bundle, null, null);
|
bundle = bundle.container;
|
||||||
// TODO
|
|
||||||
// The resPath of the resolved bundle should reflect the resource path
|
|
||||||
// requested by caller. However, overwriting resPath here will affect cached
|
|
||||||
// resource instance. The resPath is exposed by ICUResourceBundle#getResPath,
|
|
||||||
// but there are no call sites in ICU (and ICUResourceBundle is an implementation
|
|
||||||
// class). We may create a safe clone to overwrite the resPath field, but
|
|
||||||
// it has no benefit at least for now. -Yoshito
|
|
||||||
//if (sub != null) {
|
|
||||||
// sub.resPath = resPath;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
sub = ICUResourceBundle.findResourceWithFallback(keyPath, bundle, null);
|
||||||
}else{
|
}else{
|
||||||
if (locale == null) {
|
if (locale == null) {
|
||||||
// {dlf} must use requestor's class loader to get resources from same jar
|
// {dlf} must use requestor's class loader to get resources from same jar
|
||||||
@ -1241,211 +1378,54 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
loaderToUse, false);
|
loaderToUse, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringTokenizer st = new StringTokenizer(keyPath, "/");
|
int numKeys;
|
||||||
ICUResourceBundle current = bundle;
|
if (keyPath != null) {
|
||||||
while (st.hasMoreTokens()) {
|
numKeys = countPathKeys(keyPath);
|
||||||
String subKey = st.nextToken();
|
if (numKeys > 0) {
|
||||||
sub = (ICUResourceBundle)current.get(subKey, table, requested);
|
keys = new String[numKeys];
|
||||||
if (sub == null) {
|
getResPathKeys(keyPath, numKeys, keys, 0);
|
||||||
break;
|
}
|
||||||
|
} else if (keys != null) {
|
||||||
|
numKeys = depth;
|
||||||
|
} else {
|
||||||
|
depth = base.getResDepth();
|
||||||
|
numKeys = depth + 1;
|
||||||
|
keys = new String[numKeys];
|
||||||
|
base.getResPathKeys(keys, depth);
|
||||||
|
keys[depth] = key;
|
||||||
|
}
|
||||||
|
if (numKeys > 0) {
|
||||||
|
sub = bundle;
|
||||||
|
for (int i = 0; sub != null && i < numKeys; ++i) {
|
||||||
|
sub = (ICUResourceBundle)sub.get(keys[i], aliasesVisited, requested);
|
||||||
}
|
}
|
||||||
current = sub;
|
|
||||||
}
|
}
|
||||||
// TODO
|
|
||||||
// See the comments above.
|
|
||||||
//if (sub != null) {
|
|
||||||
// sub.resPath = resPath;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
if (sub == null) {
|
if (sub == null) {
|
||||||
throw new MissingResourceException(localeID, baseName, key);
|
throw new MissingResourceException(wholeBundle.localeID, wholeBundle.baseName, key);
|
||||||
}
|
}
|
||||||
|
// TODO: If we know that sub is not cached,
|
||||||
|
// then we should set its container and key to the alias' location,
|
||||||
|
// so that it behaves as if its value had been copied into the alias location.
|
||||||
|
// However, findResourceWithFallback() must reroute its bundle and key path
|
||||||
|
// to where the alias data comes from.
|
||||||
return sub;
|
return sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resource bundle lookup cache, which may be used by subclasses
|
|
||||||
// which have nested resources
|
|
||||||
protected ICUCache<Object, UResourceBundle> lookup;
|
|
||||||
private static final int MAX_INITIAL_LOOKUP_SIZE = 64;
|
|
||||||
|
|
||||||
protected void createLookupCache() {
|
|
||||||
lookup = new SimpleCache<Object, UResourceBundle>(ICUCache.WEAK, Math.max(getSize()*2, MAX_INITIAL_LOOKUP_SIZE));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UResourceBundle handleGet(String resKey, HashMap<String, String> table, UResourceBundle requested) {
|
|
||||||
UResourceBundle res = null;
|
|
||||||
if (lookup != null) {
|
|
||||||
res = lookup.get(resKey);
|
|
||||||
}
|
|
||||||
if (res == null) {
|
|
||||||
int[] index = new int[1];
|
|
||||||
boolean[] alias = new boolean[1];
|
|
||||||
res = handleGetImpl(resKey, table, requested, index, alias);
|
|
||||||
if (res != null && lookup != null && !alias[0]) {
|
|
||||||
// We do not want to cache a result from alias entry
|
|
||||||
lookup.put(resKey, res);
|
|
||||||
lookup.put(Integer.valueOf(index[0]), res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UResourceBundle handleGet(int index, HashMap<String, String> table, UResourceBundle requested) {
|
|
||||||
UResourceBundle res = null;
|
|
||||||
Integer indexKey = null;
|
|
||||||
if (lookup != null) {
|
|
||||||
indexKey = Integer.valueOf(index);
|
|
||||||
res = lookup.get(indexKey);
|
|
||||||
}
|
|
||||||
if (res == null) {
|
|
||||||
boolean[] alias = new boolean[1];
|
|
||||||
res = handleGetImpl(index, table, requested, alias);
|
|
||||||
if (res != null && lookup != null && !alias[0]) {
|
|
||||||
// We do not want to cache a result from alias entry
|
|
||||||
lookup.put(res.getKey(), res);
|
|
||||||
lookup.put(indexKey, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subclass which supports key based resource access to implement this method
|
|
||||||
protected UResourceBundle handleGetImpl(String resKey, HashMap<String, String> table, UResourceBundle requested,
|
|
||||||
int[] index, boolean[] isAlias) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subclass which supports index based resource access to implement this method
|
|
||||||
protected UResourceBundle handleGetImpl(int index, HashMap<String, String> table, UResourceBundle requested,
|
|
||||||
boolean[] isAlias) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO Below is a set of workarounds created for org.unicode.cldr.icu.ICU2LDMLWriter
|
|
||||||
/*
|
|
||||||
* Calling getKeys() on a table that has alias's can throw a NullPointerException if parent is not set,
|
|
||||||
* see trac bug: 6514
|
|
||||||
* -Brian Rower - IBM - Sept. 2008
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the resource handle for the given key within the calling resource table.
|
* @internal
|
||||||
*
|
* @deprecated This API is ICU internal only.
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
*/
|
||||||
protected int getTableResource(String resKey) {
|
public final Set<String> getTopLevelKeySet() {
|
||||||
return RES_BOGUS;
|
return wholeBundle.topLevelKeys;
|
||||||
}
|
|
||||||
protected int getTableResource(int index) {
|
|
||||||
return RES_BOGUS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the object at the specified index of the calling resource table
|
* @internal
|
||||||
* is an alias. If it is, returns true
|
* @deprecated This API is ICU internal only.
|
||||||
*
|
|
||||||
* @param index The index of the resource to check
|
|
||||||
* @returns True if the resource at 'index' is an alias, false otherwise.
|
|
||||||
*
|
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
*/
|
||||||
public boolean isAlias(int index)
|
public final void setTopLevelKeySet(Set<String> keySet) {
|
||||||
{
|
wholeBundle.topLevelKeys = keySet;
|
||||||
//TODO this is part of a workaround for ticket #6514
|
|
||||||
//if index is out of the resource, return false.
|
|
||||||
return ICUResourceBundleReader.RES_GET_TYPE(getTableResource(index)) == ALIAS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
|
||||||
public boolean isAlias()
|
|
||||||
{
|
|
||||||
//TODO this is part of a workaround for ticket #6514
|
|
||||||
return ICUResourceBundleReader.RES_GET_TYPE(resource) == ALIAS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the object with the specified key
|
|
||||||
* is an alias. If it is, returns true
|
|
||||||
*
|
|
||||||
* @returns True if the resource with 'key' is an alias, false otherwise.
|
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
|
||||||
public boolean isAlias(String k)
|
|
||||||
{
|
|
||||||
//TODO this is part of a workaround for ticket #6514
|
|
||||||
//this only applies to tables
|
|
||||||
return ICUResourceBundleReader.RES_GET_TYPE(getTableResource(k)) == ALIAS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method can be used to retrieve the underlying alias path (aka where the alias points to)
|
|
||||||
* This method was written to allow conversion from ICU back to LDML format.
|
|
||||||
*
|
|
||||||
* @param index The index where the alias path points to.
|
|
||||||
* @return The alias path.
|
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
|
||||||
public String getAliasPath(int index)
|
|
||||||
{
|
|
||||||
return getAliasValue(getTableResource(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
|
||||||
public String getAliasPath()
|
|
||||||
{
|
|
||||||
//TODO cannot allow alias path to end up in public API
|
|
||||||
return getAliasValue(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
|
||||||
public String getAliasPath(String k)
|
|
||||||
{
|
|
||||||
//TODO cannot allow alias path to end up in public API
|
|
||||||
return getAliasValue(getTableResource(k));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method for getKeysSafe
|
|
||||||
*/
|
|
||||||
protected String getKey(int index) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an Enumeration of the keys belonging to this table or array.
|
|
||||||
* This method differs from the getKeys() method by not following alias paths. This method exposes
|
|
||||||
* underlying alias's. For all general purposes of the ICU resource bundle please use getKeys().
|
|
||||||
*
|
|
||||||
* @return Keys in this table or array.
|
|
||||||
* @author Brian Rower
|
|
||||||
*/
|
|
||||||
public Enumeration<String> getKeysSafe()
|
|
||||||
{
|
|
||||||
//TODO this is part of a workaround for ticket #6514
|
|
||||||
//the safeness only applies to tables, so use the other method if it's not a table
|
|
||||||
if(!ICUResourceBundleReader.URES_IS_TABLE(resource))
|
|
||||||
{
|
|
||||||
return getKeys();
|
|
||||||
}
|
|
||||||
List<String> v = new ArrayList<String>();
|
|
||||||
int size = getSize();
|
|
||||||
for(int index = 0; index < size; index++)
|
|
||||||
{
|
|
||||||
String curKey = getKey(index);
|
|
||||||
v.add(curKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO we should use Iterator or List as the return type
|
|
||||||
// instead of Enumeration
|
|
||||||
|
|
||||||
return Collections.enumeration(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the worker function for the public getKeys().
|
// This is the worker function for the public getKeys().
|
||||||
@ -1459,6 +1439,6 @@ public class ICUResourceBundle extends UResourceBundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isTopLevelResource() {
|
protected boolean isTopLevelResource() {
|
||||||
return resPath.length() == 0;
|
return container == null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,41 +15,35 @@ import com.ibm.icu.util.UResourceBundle;
|
|||||||
import com.ibm.icu.util.UResourceTypeMismatchException;
|
import com.ibm.icu.util.UResourceTypeMismatchException;
|
||||||
|
|
||||||
class ICUResourceBundleImpl extends ICUResourceBundle {
|
class ICUResourceBundleImpl extends ICUResourceBundle {
|
||||||
protected ICUResourceBundleImpl(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
protected ICUResourceBundleImpl(ICUResourceBundleImpl container, String key) {
|
||||||
ICUResourceBundleImpl container) {
|
super(container, key);
|
||||||
super(reader, key, resPath, resource, container);
|
}
|
||||||
|
ICUResourceBundleImpl(WholeBundle wholeBundle) {
|
||||||
|
super(wholeBundle);
|
||||||
}
|
}
|
||||||
protected final ICUResourceBundle createBundleObject(String _key,
|
protected final ICUResourceBundle createBundleObject(String _key,
|
||||||
int _resource,
|
int _resource,
|
||||||
HashMap<String, String> table,
|
HashMap<String, String> aliasesVisited,
|
||||||
UResourceBundle requested,
|
UResourceBundle requested) {
|
||||||
boolean[] isAlias) {
|
|
||||||
if (isAlias != null) {
|
|
||||||
isAlias[0] = false;
|
|
||||||
}
|
|
||||||
String _resPath = resPath + "/" + _key;
|
|
||||||
switch(ICUResourceBundleReader.RES_GET_TYPE(_resource)) {
|
switch(ICUResourceBundleReader.RES_GET_TYPE(_resource)) {
|
||||||
case STRING :
|
case STRING :
|
||||||
case STRING_V2:
|
case STRING_V2:
|
||||||
return new ICUResourceBundleImpl.ResourceString(reader, _key, _resPath, _resource, this);
|
return new ICUResourceBundleImpl.ResourceString(this, _key, _resource);
|
||||||
case BINARY:
|
case BINARY:
|
||||||
return new ICUResourceBundleImpl.ResourceBinary(reader, _key, _resPath, _resource, this);
|
return new ICUResourceBundleImpl.ResourceBinary(this, _key, _resource);
|
||||||
case ALIAS:
|
case ALIAS:
|
||||||
if (isAlias != null) {
|
return getAliasedResource(this, null, 0, _key, _resource, aliasesVisited, requested);
|
||||||
isAlias[0] = true;
|
|
||||||
}
|
|
||||||
return findResource(_key, _resPath, _resource, table, requested);
|
|
||||||
case INT:
|
case INT:
|
||||||
return new ICUResourceBundleImpl.ResourceInt(reader, _key, _resPath, _resource, this);
|
return new ICUResourceBundleImpl.ResourceInt(this, _key, _resource);
|
||||||
case INT_VECTOR:
|
case INT_VECTOR:
|
||||||
return new ICUResourceBundleImpl.ResourceIntVector(reader, _key, _resPath, _resource, this);
|
return new ICUResourceBundleImpl.ResourceIntVector(this, _key, _resource);
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
case ARRAY16:
|
case ARRAY16:
|
||||||
return new ICUResourceBundleImpl.ResourceArray(reader, _key, _resPath, _resource, this);
|
return new ICUResourceBundleImpl.ResourceArray(this, _key, _resource);
|
||||||
case TABLE:
|
case TABLE:
|
||||||
case TABLE16:
|
case TABLE16:
|
||||||
case TABLE32:
|
case TABLE32:
|
||||||
return new ICUResourceBundleImpl.ResourceTable(reader, _key, _resPath, _resource, this);
|
return new ICUResourceBundleImpl.ResourceTable(this, _key, _resource);
|
||||||
default :
|
default :
|
||||||
throw new IllegalStateException("The resource type is unknown");
|
throw new IllegalStateException("The resource type is unknown");
|
||||||
}
|
}
|
||||||
@ -58,41 +52,53 @@ class ICUResourceBundleImpl extends ICUResourceBundle {
|
|||||||
// Scalar values ------------------------------------------------------- ***
|
// Scalar values ------------------------------------------------------- ***
|
||||||
|
|
||||||
private static final class ResourceBinary extends ICUResourceBundleImpl {
|
private static final class ResourceBinary extends ICUResourceBundleImpl {
|
||||||
|
private int resource;
|
||||||
|
public int getType() {
|
||||||
|
return BINARY;
|
||||||
|
}
|
||||||
public ByteBuffer getBinary() {
|
public ByteBuffer getBinary() {
|
||||||
return reader.getBinary(resource);
|
return wholeBundle.reader.getBinary(resource);
|
||||||
}
|
}
|
||||||
public byte [] getBinary(byte []ba) {
|
public byte [] getBinary(byte []ba) {
|
||||||
return reader.getBinary(resource, ba);
|
return wholeBundle.reader.getBinary(resource, ba);
|
||||||
}
|
}
|
||||||
ResourceBinary(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
ResourceBinary(ICUResourceBundleImpl container, String key, int resource) {
|
||||||
ICUResourceBundleImpl container) {
|
super(container, key);
|
||||||
super(reader, key, resPath, resource, container);
|
this.resource = resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static final class ResourceInt extends ICUResourceBundleImpl {
|
private static final class ResourceInt extends ICUResourceBundleImpl {
|
||||||
|
private int resource;
|
||||||
|
public int getType() {
|
||||||
|
return INT;
|
||||||
|
}
|
||||||
public int getInt() {
|
public int getInt() {
|
||||||
return ICUResourceBundleReader.RES_GET_INT(resource);
|
return ICUResourceBundleReader.RES_GET_INT(resource);
|
||||||
}
|
}
|
||||||
public int getUInt() {
|
public int getUInt() {
|
||||||
return ICUResourceBundleReader.RES_GET_UINT(resource);
|
return ICUResourceBundleReader.RES_GET_UINT(resource);
|
||||||
}
|
}
|
||||||
ResourceInt(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
ResourceInt(ICUResourceBundleImpl container, String key, int resource) {
|
||||||
ICUResourceBundleImpl container) {
|
super(container, key);
|
||||||
super(reader, key, resPath, resource, container);
|
this.resource = resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static final class ResourceString extends ICUResourceBundleImpl {
|
private static final class ResourceString extends ICUResourceBundleImpl {
|
||||||
|
private int resource;
|
||||||
private String value;
|
private String value;
|
||||||
|
public int getType() {
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
public String getString() {
|
public String getString() {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
return reader.getString(resource);
|
return wholeBundle.reader.getString(resource);
|
||||||
}
|
}
|
||||||
ResourceString(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
ResourceString(ICUResourceBundleImpl container, String key, int resource) {
|
||||||
ICUResourceBundleImpl container) {
|
super(container, key);
|
||||||
super(reader, key, resPath, resource, container);
|
this.resource = resource;
|
||||||
String s = reader.getString(resource);
|
String s = wholeBundle.reader.getString(resource);
|
||||||
// Allow the reader cache's SoftReference to do its job.
|
// Allow the reader cache's SoftReference to do its job.
|
||||||
if (s.length() < ICUResourceBundleReader.LARGE_SIZE / 2) {
|
if (s.length() < ICUResourceBundleReader.LARGE_SIZE / 2) {
|
||||||
value = s;
|
value = s;
|
||||||
@ -100,18 +106,22 @@ class ICUResourceBundleImpl extends ICUResourceBundle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static final class ResourceIntVector extends ICUResourceBundleImpl {
|
private static final class ResourceIntVector extends ICUResourceBundleImpl {
|
||||||
public int[] getIntVector() {
|
private int resource;
|
||||||
return reader.getIntVector(resource);
|
public int getType() {
|
||||||
|
return INT_VECTOR;
|
||||||
}
|
}
|
||||||
ResourceIntVector(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
public int[] getIntVector() {
|
||||||
ICUResourceBundleImpl container) {
|
return wholeBundle.reader.getIntVector(resource);
|
||||||
super(reader, key, resPath, resource, container);
|
}
|
||||||
|
ResourceIntVector(ICUResourceBundleImpl container, String key, int resource) {
|
||||||
|
super(container, key);
|
||||||
|
this.resource = resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Container values ---------------------------------------------------- ***
|
// Container values ---------------------------------------------------- ***
|
||||||
|
|
||||||
private static class ResourceContainer extends ICUResourceBundleImpl {
|
static abstract class ResourceContainer extends ICUResourceBundleImpl {
|
||||||
protected ICUResourceBundleReader.Container value;
|
protected ICUResourceBundleReader.Container value;
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
@ -119,34 +129,41 @@ class ICUResourceBundleImpl extends ICUResourceBundle {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String getString(int index) {
|
public String getString(int index) {
|
||||||
int res = value.getContainerResource(reader, index);
|
int res = value.getContainerResource(wholeBundle.reader, index);
|
||||||
if (res == RES_BOGUS) {
|
if (res == RES_BOGUS) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
String s = reader.getString(res);
|
String s = wholeBundle.reader.getString(res);
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
return super.getString(index);
|
return super.getString(index);
|
||||||
}
|
}
|
||||||
protected int getContainerResource(int index) {
|
protected int getContainerResource(int index) {
|
||||||
return value.getContainerResource(reader, index);
|
return value.getContainerResource(wholeBundle.reader, index);
|
||||||
}
|
}
|
||||||
protected UResourceBundle createBundleObject(int index, String resKey, HashMap<String, String> table,
|
protected UResourceBundle createBundleObject(int index, String resKey, HashMap<String, String> aliasesVisited,
|
||||||
UResourceBundle requested, boolean[] isAlias) {
|
UResourceBundle requested) {
|
||||||
int item = getContainerResource(index);
|
int item = getContainerResource(index);
|
||||||
if (item == RES_BOGUS) {
|
if (item == RES_BOGUS) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
return createBundleObject(resKey, item, table, requested, isAlias);
|
return createBundleObject(resKey, item, aliasesVisited, requested);
|
||||||
}
|
}
|
||||||
ResourceContainer(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
|
||||||
ICUResourceBundleImpl container) {
|
ResourceContainer(ICUResourceBundleImpl container, String key) {
|
||||||
super(reader, key, resPath, resource, container);
|
super(container, key);
|
||||||
|
}
|
||||||
|
ResourceContainer(WholeBundle wholeBundle) {
|
||||||
|
super(wholeBundle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static class ResourceArray extends ResourceContainer {
|
private static class ResourceArray extends ResourceContainer {
|
||||||
|
public int getType() {
|
||||||
|
return ARRAY;
|
||||||
|
}
|
||||||
protected String[] handleGetStringArray() {
|
protected String[] handleGetStringArray() {
|
||||||
|
ICUResourceBundleReader reader = wholeBundle.reader;
|
||||||
int length = value.getSize();
|
int length = value.getSize();
|
||||||
String[] strings = new String[length];
|
String[] strings = new String[length];
|
||||||
for (int i = 0; i < length; ++i) {
|
for (int i = 0; i < length; ++i) {
|
||||||
@ -161,34 +178,31 @@ class ICUResourceBundleImpl extends ICUResourceBundle {
|
|||||||
public String[] getStringArray() {
|
public String[] getStringArray() {
|
||||||
return handleGetStringArray();
|
return handleGetStringArray();
|
||||||
}
|
}
|
||||||
protected UResourceBundle handleGetImpl(String indexStr, HashMap<String, String> table,
|
@Override
|
||||||
UResourceBundle requested,
|
protected UResourceBundle handleGet(String indexStr, HashMap<String, String> aliasesVisited,
|
||||||
int[] index, boolean[] isAlias) {
|
UResourceBundle requested) {
|
||||||
int i = indexStr.length() > 0 ? Integer.valueOf(indexStr).intValue() : -1;
|
int i = Integer.parseInt(indexStr);
|
||||||
if(index != null) {
|
return createBundleObject(i, indexStr, aliasesVisited, requested);
|
||||||
index[0] = i;
|
|
||||||
}
|
|
||||||
if (i < 0) {
|
|
||||||
throw new UResourceTypeMismatchException("Could not get the correct value for index: "+ indexStr);
|
|
||||||
}
|
|
||||||
return createBundleObject(i, indexStr, table, requested, isAlias);
|
|
||||||
}
|
}
|
||||||
protected UResourceBundle handleGetImpl(int index, HashMap<String, String> table,
|
@Override
|
||||||
UResourceBundle requested, boolean[] isAlias) {
|
protected UResourceBundle handleGet(int index, HashMap<String, String> aliasesVisited,
|
||||||
return createBundleObject(index, Integer.toString(index), table, requested, isAlias);
|
UResourceBundle requested) {
|
||||||
|
return createBundleObject(index, Integer.toString(index), aliasesVisited, requested);
|
||||||
}
|
}
|
||||||
ResourceArray(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
ResourceArray(ICUResourceBundleImpl container, String key, int resource) {
|
||||||
ICUResourceBundleImpl container) {
|
super(container, key);
|
||||||
super(reader, key, resPath, resource, container);
|
value = wholeBundle.reader.getArray(resource);
|
||||||
value = reader.getArray(resource);
|
|
||||||
createLookupCache(); // Use bundle cache to access array entries
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static class ResourceTable extends ResourceContainer {
|
static class ResourceTable extends ResourceContainer {
|
||||||
|
public int getType() {
|
||||||
|
return TABLE;
|
||||||
|
}
|
||||||
protected String getKey(int index) {
|
protected String getKey(int index) {
|
||||||
return ((ICUResourceBundleReader.Table)value).getKey(reader, index);
|
return ((ICUResourceBundleReader.Table)value).getKey(wholeBundle.reader, index);
|
||||||
}
|
}
|
||||||
protected Set<String> handleKeySet() {
|
protected Set<String> handleKeySet() {
|
||||||
|
ICUResourceBundleReader reader = wholeBundle.reader;
|
||||||
TreeSet<String> keySet = new TreeSet<String>();
|
TreeSet<String> keySet = new TreeSet<String>();
|
||||||
ICUResourceBundleReader.Table table = (ICUResourceBundleReader.Table)value;
|
ICUResourceBundleReader.Table table = (ICUResourceBundleReader.Table)value;
|
||||||
for (int i = 0; i < table.getSize(); ++i) {
|
for (int i = 0; i < table.getSize(); ++i) {
|
||||||
@ -196,31 +210,23 @@ class ICUResourceBundleImpl extends ICUResourceBundle {
|
|||||||
}
|
}
|
||||||
return keySet;
|
return keySet;
|
||||||
}
|
}
|
||||||
protected int getTableResource(String resKey) {
|
@Override
|
||||||
return ((ICUResourceBundleReader.Table)value).getTableResource(reader, resKey);
|
protected UResourceBundle handleGet(String resKey, HashMap<String, String> aliasesVisited,
|
||||||
}
|
UResourceBundle requested) {
|
||||||
protected int getTableResource(int index) {
|
int i = ((ICUResourceBundleReader.Table)value).findTableItem(wholeBundle.reader, resKey);
|
||||||
return getContainerResource(index);
|
|
||||||
}
|
|
||||||
protected UResourceBundle handleGetImpl(String resKey, HashMap<String, String> table,
|
|
||||||
UResourceBundle requested,
|
|
||||||
int[] index, boolean[] isAlias) {
|
|
||||||
int i = ((ICUResourceBundleReader.Table)value).findTableItem(reader, resKey);
|
|
||||||
if(index != null) {
|
|
||||||
index[0] = i;
|
|
||||||
}
|
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return createBundleObject(i, resKey, table, requested, isAlias);
|
return createBundleObject(resKey, getContainerResource(i), aliasesVisited, requested);
|
||||||
}
|
}
|
||||||
protected UResourceBundle handleGetImpl(int index, HashMap<String, String> table,
|
@Override
|
||||||
UResourceBundle requested, boolean[] isAlias) {
|
protected UResourceBundle handleGet(int index, HashMap<String, String> aliasesVisited,
|
||||||
String itemKey = ((ICUResourceBundleReader.Table)value).getKey(reader, index);
|
UResourceBundle requested) {
|
||||||
|
String itemKey = ((ICUResourceBundleReader.Table)value).getKey(wholeBundle.reader, index);
|
||||||
if (itemKey == null) {
|
if (itemKey == null) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
return createBundleObject(index, itemKey, table, requested, isAlias);
|
return createBundleObject(itemKey, getContainerResource(index), aliasesVisited, requested);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected Object handleGetObject(String key) {
|
protected Object handleGetObject(String key) {
|
||||||
@ -228,6 +234,7 @@ class ICUResourceBundleImpl extends ICUResourceBundle {
|
|||||||
// It would be even better if we could override getString(key)/getStringArray(key),
|
// It would be even better if we could override getString(key)/getStringArray(key),
|
||||||
// so that we know the expected object type,
|
// so that we know the expected object type,
|
||||||
// but those are final in java.util.ResourceBundle.
|
// but those are final in java.util.ResourceBundle.
|
||||||
|
ICUResourceBundleReader reader = wholeBundle.reader;
|
||||||
int index = ((ICUResourceBundleReader.Table)value).findTableItem(reader, key);
|
int index = ((ICUResourceBundleReader.Table)value).findTableItem(reader, key);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
int res = value.getContainerResource(reader, index);
|
int res = value.getContainerResource(reader, index);
|
||||||
@ -261,18 +268,24 @@ class ICUResourceBundleImpl extends ICUResourceBundle {
|
|||||||
/**
|
/**
|
||||||
* Returns a String if found, or null if not found or if the key item is not a string.
|
* Returns a String if found, or null if not found or if the key item is not a string.
|
||||||
*/
|
*/
|
||||||
String getStringOrNull(String key) {
|
String findString(String key) {
|
||||||
|
ICUResourceBundleReader reader = wholeBundle.reader;
|
||||||
int index = ((ICUResourceBundleReader.Table)value).findTableItem(reader, key);
|
int index = ((ICUResourceBundleReader.Table)value).findTableItem(reader, key);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return reader.getString(value.getContainerResource(reader, index));
|
return reader.getString(value.getContainerResource(reader, index));
|
||||||
}
|
}
|
||||||
ResourceTable(ICUResourceBundleReader reader, String key, String resPath, int resource,
|
ResourceTable(ICUResourceBundleImpl container, String key, int resource) {
|
||||||
ICUResourceBundleImpl container) {
|
super(container, key);
|
||||||
super(reader, key, resPath, resource, container);
|
value = wholeBundle.reader.getTable(resource);
|
||||||
value = reader.getTable(resource);
|
}
|
||||||
createLookupCache(); // Use bundle cache to access table entries
|
/**
|
||||||
|
* Constructor for the root table of a bundle.
|
||||||
|
*/
|
||||||
|
ResourceTable(WholeBundle wholeBundle, int rootRes) {
|
||||||
|
super(wholeBundle);
|
||||||
|
value = wholeBundle.reader.getTable(rootRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ public final class ICUResourceBundleReader {
|
|||||||
static int RES_GET_UINT(int res) {
|
static int RES_GET_UINT(int res) {
|
||||||
return res & 0x0fffffff;
|
return res & 0x0fffffff;
|
||||||
}
|
}
|
||||||
private static boolean URES_IS_ARRAY(int type) {
|
static boolean URES_IS_ARRAY(int type) {
|
||||||
return type == UResourceBundle.ARRAY || type == ICUResourceBundle.ARRAY16;
|
return type == UResourceBundle.ARRAY || type == ICUResourceBundle.ARRAY16;
|
||||||
}
|
}
|
||||||
static boolean URES_IS_TABLE(int type) {
|
static boolean URES_IS_TABLE(int type) {
|
||||||
@ -843,6 +843,9 @@ public final class ICUResourceBundleReader {
|
|||||||
}
|
}
|
||||||
return reader.getInt(itemsOffset + 4 * index);
|
return reader.getInt(itemsOffset + 4 * index);
|
||||||
}
|
}
|
||||||
|
int getResource(ICUResourceBundleReader reader, String resKey) {
|
||||||
|
return getContainerResource(reader, Integer.parseInt(resKey));
|
||||||
|
}
|
||||||
Container() {
|
Container() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -905,7 +908,8 @@ public final class ICUResourceBundleReader {
|
|||||||
}
|
}
|
||||||
return URESDATA_ITEM_NOT_FOUND; /* not found or table is empty. */
|
return URESDATA_ITEM_NOT_FOUND; /* not found or table is empty. */
|
||||||
}
|
}
|
||||||
int getTableResource(ICUResourceBundleReader reader, String resKey) {
|
@Override
|
||||||
|
int getResource(ICUResourceBundleReader reader, String resKey) {
|
||||||
return getContainerResource(reader, findTableItem(reader, resKey));
|
return getContainerResource(reader, findTableItem(reader, resKey));
|
||||||
}
|
}
|
||||||
Table() {
|
Table() {
|
||||||
|
@ -823,6 +823,19 @@ public abstract class UResourceBundle extends ResourceBundle {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public Set<String> keySet() {
|
public Set<String> keySet() {
|
||||||
|
// TODO: Java 6 ResourceBundle has keySet() which calls handleKeySet()
|
||||||
|
// and caches the results.
|
||||||
|
// When we upgrade to Java 6, we still need to check for isTopLevelResource().
|
||||||
|
// Keep the else branch as is. The if body should just return super.keySet().
|
||||||
|
// Remove then-redundant caching of the keys.
|
||||||
|
Set<String> keys = null;
|
||||||
|
ICUResourceBundle icurb = null;
|
||||||
|
if(isTopLevelResource() && this instanceof ICUResourceBundle) {
|
||||||
|
// We do not cache the top-level keys in this base class so that
|
||||||
|
// not every string/int/binary... resource has to have a keys cache field.
|
||||||
|
icurb = (ICUResourceBundle)this;
|
||||||
|
keys = icurb.getTopLevelKeySet();
|
||||||
|
}
|
||||||
if(keys == null) {
|
if(keys == null) {
|
||||||
if(isTopLevelResource()) {
|
if(isTopLevelResource()) {
|
||||||
TreeSet<String> newKeySet;
|
TreeSet<String> newKeySet;
|
||||||
@ -841,6 +854,9 @@ public abstract class UResourceBundle extends ResourceBundle {
|
|||||||
}
|
}
|
||||||
newKeySet.addAll(handleKeySet());
|
newKeySet.addAll(handleKeySet());
|
||||||
keys = Collections.unmodifiableSet(newKeySet);
|
keys = Collections.unmodifiableSet(newKeySet);
|
||||||
|
if(icurb != null) {
|
||||||
|
icurb.setTopLevelKeySet(keys);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return handleKeySet();
|
return handleKeySet();
|
||||||
}
|
}
|
||||||
@ -848,7 +864,6 @@ public abstract class UResourceBundle extends ResourceBundle {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> keys = null;
|
|
||||||
/**
|
/**
|
||||||
* Returns a Set of the keys contained <i>only</i> in this ResourceBundle.
|
* Returns a Set of the keys contained <i>only</i> in this ResourceBundle.
|
||||||
* This does not include further keys from parent bundles.
|
* This does not include further keys from parent bundles.
|
||||||
@ -969,14 +984,14 @@ public abstract class UResourceBundle extends ResourceBundle {
|
|||||||
* {@icu} Actual worker method for fetching a resource based on the given key.
|
* {@icu} Actual worker method for fetching a resource based on the given key.
|
||||||
* Sub classes must override this method if they support resources with keys.
|
* Sub classes must override this method if they support resources with keys.
|
||||||
* @param aKey the key string of the resource to be fetched
|
* @param aKey the key string of the resource to be fetched
|
||||||
* @param table hashtable object to hold references of resources already seen
|
* @param aliasesVisited hashtable object to hold references of resources already seen
|
||||||
* @param requested the original resource bundle object on which the get method was invoked.
|
* @param requested the original resource bundle object on which the get method was invoked.
|
||||||
* The requested bundle and the bundle on which this method is invoked
|
* The requested bundle and the bundle on which this method is invoked
|
||||||
* are the same, except in the cases where aliases are involved.
|
* are the same, except in the cases where aliases are involved.
|
||||||
* @return UResourceBundle a resource associated with the key
|
* @return UResourceBundle a resource associated with the key
|
||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
protected UResourceBundle handleGet(String aKey, HashMap<String, String> table,
|
protected UResourceBundle handleGet(String aKey, HashMap<String, String> aliasesVisited,
|
||||||
UResourceBundle requested) {
|
UResourceBundle requested) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -985,14 +1000,14 @@ public abstract class UResourceBundle extends ResourceBundle {
|
|||||||
* {@icu} Actual worker method for fetching a resource based on the given index.
|
* {@icu} Actual worker method for fetching a resource based on the given index.
|
||||||
* Sub classes must override this method if they support arrays of resources.
|
* Sub classes must override this method if they support arrays of resources.
|
||||||
* @param index the index of the resource to be fetched
|
* @param index the index of the resource to be fetched
|
||||||
* @param table hashtable object to hold references of resources already seen
|
* @param aliasesVisited hashtable object to hold references of resources already seen
|
||||||
* @param requested the original resource bundle object on which the get method was invoked.
|
* @param requested the original resource bundle object on which the get method was invoked.
|
||||||
* The requested bundle and the bundle on which this method is invoked
|
* The requested bundle and the bundle on which this method is invoked
|
||||||
* are the same, except in the cases where aliases are involved.
|
* are the same, except in the cases where aliases are involved.
|
||||||
* @return UResourceBundle a resource associated with the index
|
* @return UResourceBundle a resource associated with the index
|
||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
protected UResourceBundle handleGet(int index, HashMap<String, String> table,
|
protected UResourceBundle handleGet(int index, HashMap<String, String> aliasesVisited,
|
||||||
UResourceBundle requested) {
|
UResourceBundle requested) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* Copyright (C) 2001-2013, International Business Machines Corporation and *
|
* Copyright (C) 2001-2014, International Business Machines Corporation and
|
||||||
* others. All Rights Reserved. *
|
* others. All Rights Reserved.
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
*/
|
*/
|
||||||
package com.ibm.icu.dev.test.util;
|
package com.ibm.icu.dev.test.util;
|
||||||
@ -39,7 +39,6 @@ public final class ICUResourceBundleTest extends TestFmwk {
|
|||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
ICUResourceBundleTest test = new ICUResourceBundleTest();
|
ICUResourceBundleTest test = new ICUResourceBundleTest();
|
||||||
test.run(args);
|
test.run(args);
|
||||||
|
|
||||||
}
|
}
|
||||||
public void TestGetResources(){
|
public void TestGetResources(){
|
||||||
try{
|
try{
|
||||||
@ -681,20 +680,20 @@ public final class ICUResourceBundleTest extends TestFmwk {
|
|||||||
ULocale[] locales = ULocale.getAvailableLocales();
|
ULocale[] locales = ULocale.getAvailableLocales();
|
||||||
for (int i = 0; i < locales.length; ++i) {
|
for (int i = 0; i < locales.length; ++i) {
|
||||||
if (!hasLocalizedCountryFor(ULocale.ENGLISH, locales[i]) && (locales[i].getLanguage().compareTo("ti") != 0)){ // TODO: restore test for ti_* when cldrbug 3058 is fixed
|
if (!hasLocalizedCountryFor(ULocale.ENGLISH, locales[i]) && (locales[i].getLanguage().compareTo("ti") != 0)){ // TODO: restore test for ti_* when cldrbug 3058 is fixed
|
||||||
errln("Could not get localized country for "+ locales[i]);
|
errln("Could not get English localized country for " + locales[i]);
|
||||||
}
|
}
|
||||||
if(!hasLocalizedLanguageFor(ULocale.ENGLISH, locales[i])){
|
if(!hasLocalizedLanguageFor(ULocale.ENGLISH, locales[i])){
|
||||||
errln("Could not get localized language for "+ locales[i]);
|
errln("Could not get English localized language for " + locales[i]);
|
||||||
}
|
}
|
||||||
if(!hasLocalizedCountryFor(locales[i], locales[i]) &&
|
if(!hasLocalizedCountryFor(locales[i], locales[i]) &&
|
||||||
(locales[i].getLanguage().compareTo("ti") != 0) && // TODO: restore test for ti_* when cldrbug 3058 is fixed
|
(locales[i].getLanguage().compareTo("ti") != 0) && // TODO: restore test for ti_* when cldrbug 3058 is fixed
|
||||||
(locales[i].getBaseName().compareTo("nl_CW") != 0) && // TODO: restore test for nl_CW when cldrbug 4306 is fixed
|
(locales[i].getBaseName().compareTo("nl_CW") != 0) && // TODO: restore test for nl_CW when cldrbug 4306 is fixed
|
||||||
(locales[i].getBaseName().compareTo("nl_SX") != 0) ){ // TODO: restore test for nl_SX when cldrbug 4306 is fixed
|
(locales[i].getBaseName().compareTo("nl_SX") != 0) ){ // TODO: restore test for nl_SX when cldrbug 4306 is fixed
|
||||||
errln("Could not get localized country for "+ locales[i]);
|
errln("Could not get native localized country for " + locales[i]);
|
||||||
hasLocalizedCountryFor(locales[i], locales[i]);
|
hasLocalizedCountryFor(locales[i], locales[i]);
|
||||||
}
|
}
|
||||||
if(!hasLocalizedLanguageFor(locales[i], locales[i]) && (locales[i].getLanguage().compareTo("nmg") != 0)){
|
if(!hasLocalizedLanguageFor(locales[i], locales[i]) && (locales[i].getLanguage().compareTo("nmg") != 0)){
|
||||||
errln("Could not get localized language for "+ locales[i]);
|
errln("Could not get native localized language for " + locales[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
logln(locales[i] + "\t" + locales[i].getDisplayName(ULocale.ENGLISH) + "\t" + locales[i].getDisplayName(locales[i]));
|
logln(locales[i] + "\t" + locales[i].getDisplayName(ULocale.ENGLISH) + "\t" + locales[i].getDisplayName(locales[i]));
|
||||||
@ -1141,9 +1140,6 @@ public final class ICUResourceBundleTest extends TestFmwk {
|
|||||||
if (rb7.getKey() != null) {
|
if (rb7.getKey() != null) {
|
||||||
errln("getKey() call should have returned null.");
|
errln("getKey() call should have returned null.");
|
||||||
}
|
}
|
||||||
if (((ICUResourceBundle)rb1).getResPath() == null) {
|
|
||||||
errln("Error calling getResPath().");
|
|
||||||
}
|
|
||||||
if (((ICUResourceBundle)rb1).findTopLevel(0) == null) {
|
if (((ICUResourceBundle)rb1).findTopLevel(0) == null) {
|
||||||
errln("Error calling findTopLevel().");
|
errln("Error calling findTopLevel().");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user