ICU-1982 New implementation of Alias and redirected data

X-SVN-Rev: 9122
This commit is contained in:
Ram Viswanadha 2002-07-12 21:32:53 +00:00
parent 61ba0a2fdf
commit 9a1ac0fce6
2 changed files with 412 additions and 149 deletions

View File

@ -6,31 +6,25 @@
package com.ibm.icu.impl;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ListResourceBundle;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.MissingResourceException;
import java.util.Hashtable;
public class ICUListResourceBundle extends ListResourceBundle {
private static final String ICUDATA = "ICUDATA";
private static final String ICU_BUNDLE_NAME = "LocaleElements";
private static final String ICU_PACKAGE_NAME ="com.ibm.icu.impl.data";
private static final String ENCODING="UTF-8";
protected ICUListResourceBundle() {
}
// protected static final Integer COMPRESSED_BINARY = new Integer(1);
protected static final Integer RESOURCE_BINARY = new Integer(2);
// protected static final Integer COMPRESSED_STRING = new Integer(3);
// protected static final Integer COMPRESSED_BINARY_STRING = new Integer(4);
protected static final Integer RESOURCE_UNICODE = new Integer(5);
/**
* Subclassers must statically initialize this
@ -46,151 +40,385 @@ public class ICUListResourceBundle extends ListResourceBundle {
* See base class description
*/
protected Object[][] getContents(){
// we replace any redirected values with real values in a cloned array
if (realContents == null) {
realContents = contents;
for (int i = 0; i < contents.length; ++i) {
Object newValue = getRedirectedValue(contents[i][1]);
if (newValue != null) {
if (realContents == contents) {
realContents = (Object[][])contents.clone();
// we replace any redirected values with real values in a cloned array
if (realContents == null) {
realContents = contents;
for (int i = 0; i < contents.length; ++i) {
Object newValue = getRedirectedValue((String)contents[i][0],contents[i][1]);
if (newValue != null) {
if (realContents == contents) {
realContents = (Object[][])contents.clone();
}
realContents[i] = new Object[] { contents[i][0], newValue };
}
}
realContents[i] = new Object[] { contents[i][0], newValue };
}
}
}
return realContents;
return realContents;
}
/**
* Return null if value is already in existing contents array, otherwise fetch the
* real value and return it.
*/
private Object getRedirectedValue(Object value) {
// what we really want is:
// if (value instanceof ICUListResourceBundle.Redirect) {
// return ((ICUListResourcBundle.Redirect)value).getValue();
// }
// return null;
// if we really want to support multiple encoding types, then we just have
// different instances of ICUListResourceBundle.Redirect.
// value is always an array of one object which is an array of two objects,
// encoding type and resource name.
// encoding type is always RESOURCE_BINARY or RESOURCE_UNICODE
if (value instanceof Object[][]) {
Object[][] aValue = (Object[][])value;
if (aValue.length == 1) {
Object[] bValue = (Object[])aValue[0];
String resName = (String)bValue[1];
try {
if (bValue[0] == RESOURCE_BINARY) {
// this code would be in RedirectByteArray.getValue, for example, and the resource
// value would be an instance of this class
// sigh, isn't there a better way to read the whole stream?
// could get url instead, I suppose, and get the length of the data
InputStream stream = this.getClass().getResourceAsStream(resName);
byte[] result = readToEOS(stream);
return result;
}
else if (bValue[0] == RESOURCE_UNICODE) {
// temporarily disable because of BreakDictionaryData_th.problem
// LocaleElements_th is the only resource currently using this.
return null;
/*
InputStream stream = this.getClass().getResourceAsStream(resName);
InputStreamReader reader = new InputStreamReader(stream, "UTF-16LE");
char[] result = readToEOS(reader);
return result;
*/
}
}
catch (Exception e) {
return null;
}
}
}
return null;
private Object getRedirectedValue(String key, Object value) {
if (value instanceof Object[][]) {
Object[][] aValue = (Object[][])value;
int i=0;
while(i < aValue.length){
int j=0;
while(j < aValue[i].length){
aValue[i][j] = getRedirectedValue((String)aValue[i][0],aValue[i][j]);
j++;
}
i++;
}
}else if(value instanceof Alias){
Hashtable visited = new Hashtable();
String cName = this.getClass().getName();
visited.put(cName+key,"");
return ((Alias)value).getResource(cName,key,visited);
}else if(value instanceof CompressedString){
return ((CompressedString)value).getResource();
}else if(value instanceof CompressedBinary){
return ((CompressedBinary)value).getResource();
}else if(value instanceof ResourceBinary){
return ((ResourceBinary)value).getResource(this);
}else if(value instanceof ResourceString){
try{
return ((ResourceString)value).getResource(this);
}catch(UnsupportedEncodingException e){
throw new RuntimeException(e.toString());
}
}
return value;
}
private static byte[] readToEOS(InputStream stream) {
ArrayList vec = new ArrayList();
int count = 0;
int pos = 0;
final int MAXLENGTH = 0x8000; // max buffer size - 32K
int length = 0x80; // start with small buffers and work up
do {
pos = 0;
length = length >= MAXLENGTH ? MAXLENGTH : length * 2;
byte[] buffer = new byte[length];
try {
ArrayList vec = new ArrayList();
int count = 0;
int pos = 0;
final int MAXLENGTH = 0x8000; // max buffer size - 32K
int length = 0x80; // start with small buffers and work up
do {
int n = stream.read(buffer, pos, length - pos);
if (n == -1) {
break;
pos = 0;
length = length >= MAXLENGTH ? MAXLENGTH : length * 2;
byte[] buffer = new byte[length];
try {
do {
int n = stream.read(buffer, pos, length - pos);
if (n == -1) {
break;
}
pos += n;
} while (pos < length);
}
pos += n;
} while (pos < length);
}
catch (IOException e) {
}
vec.add(buffer);
count += pos;
} while (pos == length);
byte[] data = new byte[count];
pos = 0;
for (int i = 0; i < vec.size(); ++i) {
byte[] buf = (byte[])vec.get(i);
int len = Math.min(buf.length, count - pos);
System.arraycopy(buf, 0, data, pos, len);
pos += len;
}
return data;
catch (IOException e) {
}
vec.add(buffer);
count += pos;
} while (pos == length);
byte[] data = new byte[count];
pos = 0;
for (int i = 0; i < vec.size(); ++i) {
byte[] buf = (byte[])vec.get(i);
int len = Math.min(buf.length, count - pos);
System.arraycopy(buf, 0, data, pos, len);
pos += len;
}
return data;
}
private static char[] readToEOS(InputStreamReader stream) {
ArrayList vec = new ArrayList();
int count = 0;
int pos = 0;
final int MAXLENGTH = 0x8000; // max buffer size - 32K
int length = 0x80; // start with small buffers and work up
do {
pos = 0;
length = length >= MAXLENGTH ? MAXLENGTH : length * 2;
char[] buffer = new char[length];
try {
ArrayList vec = new ArrayList();
int count = 0;
int pos = 0;
final int MAXLENGTH = 0x8000; // max buffer size - 32K
int length = 0x80; // start with small buffers and work up
do {
int n = stream.read(buffer, pos, length - pos);
if (n == -1) {
break;
pos = 0;
length = length >= MAXLENGTH ? MAXLENGTH : length * 2;
char[] buffer = new char[length];
try {
do {
int n = stream.read(buffer, pos, length - pos);
if (n == -1) {
break;
}
pos += n;
} while (pos < length);
}
pos += n;
} while (pos < length);
}
catch (IOException e) {
}
vec.add(buffer);
count += pos;
} while (pos == length);
char[] data = new char[count];
pos = 0;
for (int i = 0; i < vec.size(); ++i) {
char[] buf = (char[])vec.get(i);
int len = Math.min(buf.length, count - pos);
System.arraycopy(buf, 0, data, pos, len);
pos += len;
}
return data;
catch (IOException e) {
}
vec.add(buffer);
count += pos;
} while (pos == length);
char[] data = new char[count];
pos = 0;
for (int i = 0; i < vec.size(); ++i) {
char[] buf = (char[])vec.get(i);
int len = Math.min(buf.length, count - pos);
System.arraycopy(buf, 0, data, pos, len);
pos += len;
}
return data;
}
public static class CompressedString{
private String expanded=null;
private String compressed=null;
public CompressedString(String str){
compressed=str;
}
private Object getResource(){
if(compressed==null){
return null;
}
if(expanded==null){
expanded= new String(Utility.RLEStringToCharArray(compressed));
}
return expanded;
}
}
public static class CompressedBinary{
private byte[] expanded=null;
private String compressed=null;
public CompressedBinary(String str){
compressed = str;
}
private Object getResource(){
if(compressed==null){
return null;
}
if(expanded==null){
expanded= Utility.RLEStringToByteArray(compressed);
}
return expanded;
}
}
public static class ResourceBinary{
private byte[] expanded=null;
private String resName=null;
public ResourceBinary(String name){
resName=name;
}
public Object getResource(Object obj){
if(expanded==null){
InputStream stream = obj.getClass().getResourceAsStream(resName);
if(stream==null){
throw new MissingResourceException("",obj.getClass().getName(),resName);
}
expanded = readToEOS(stream);
}
return expanded;
}
}
public static class ResourceString{
private char[] expanded=null;
private String resName=null;
public ResourceString(String name){
resName=name;
}
public Object getResource(Object obj) throws UnsupportedEncodingException{
if(expanded==null){
// Resource strings are always UTF-8
InputStream stream = obj.getClass().getResourceAsStream(resName);
if(stream==null){
throw new MissingResourceException("",obj.getClass().getName(),resName);
}
InputStreamReader reader = new InputStreamReader(stream,ENCODING);
expanded = readToEOS(reader);
}
return new String(expanded);
}
}
public static class Alias{
public Alias(String path){
pathToResource = path;
};
private final char RES_PATH_SEP_CHAR = '/';
private String pathToResource;
private Object getResource(String className,String parentKey, Hashtable visited){
String packageName=null,bundleName=null, locale=null, keyPath=null;
if(pathToResource.indexOf(RES_PATH_SEP_CHAR)==0){
int i =pathToResource.indexOf(RES_PATH_SEP_CHAR,1);
int j =pathToResource.indexOf(RES_PATH_SEP_CHAR,i+1);
bundleName=pathToResource.substring(1,i);
locale=pathToResource.substring(i+1);
if(j!=-1){
locale=pathToResource.substring(i+1,j);
keyPath=pathToResource.substring(j+1,pathToResource.length());
}
//there is a path included
if(bundleName.equals(ICUDATA)){
bundleName = ICU_BUNDLE_NAME;
packageName = ICU_PACKAGE_NAME;
}
}else{
//no path start with locale
int i =pathToResource.indexOf(RES_PATH_SEP_CHAR);
//If this is a bundle with locale name following it
//then it should be of type <bundle name>_<locale>
//if not we donot guarantee that this will work
int j = className.lastIndexOf(".");
packageName=className.substring(0,j);
bundleName=className.substring(j+1,className.indexOf("_"));
keyPath=pathToResource.substring(i+1);
if(i!=-1){
locale = pathToResource.substring(0,i);
}else{
locale=keyPath;
keyPath=parentKey;
className=packageName+"."+bundleName+"_"+locale;
}
}
ResourceBundle bundle = null;
// getResourceBundle guarantees that the CLASSPATH will be searched
// for loading the resource with name <bundleName>_<localeName>.class
bundle = ICULocaleData.getResourceBundle(packageName,bundleName,locale);
return findResource(bundle,className,keyPath, visited);
}
private boolean isIndex(String s){
if(s.length()==1){
char c = s.charAt(0);
return Character.isDigit(c);
}
return false;
}
private int getIndex(String s){
if(s.length()==1){
char c = s.charAt(0);
if(Character.isDigit(c)){
return Integer.valueOf(s).intValue();
}
}
return -1;
}
private Object findResource(Object[][] contents, String key){
for (int i = 0; i < contents.length; ++i) {
// key must be non-null String, value must be non-null
String tempKey = (String) contents[i][0];
Object value = contents[i][1];
if (tempKey == null || value == null) {
throw new NullPointerException();
}
if(tempKey.equals(key)){
return value;
}
}
return null;
}
private Object findResource(Object o , String[] keys, int start){
Object obj = o;
int i=0;
if( start < keys.length && keys[start] !=null){
if(obj instanceof Object[][]){
obj = findResource((Object[][])obj,keys[start]);
}else if(obj instanceof Object[] && isIndex(keys[start])){
obj = ((Object[])obj)[getIndex(keys[start])];
}
if(start+1 < keys.length && keys[start+1] !=null){
obj = findResource(obj,keys,start+1);
}
}
return obj;
}
private Object findResource(ResourceBundle bundle,String className,String key, Hashtable visited){
if(key==null){
return ((ICUListResourceBundle)bundle).getContents();
}
if(visited.get(className+key)!=null){
throw new MissingResourceException("Circular Aliases in bundle.",bundle.getClass().getName(),key);
}
visited.put(className+key,"");
String[] keys = split(key,RES_PATH_SEP_CHAR);
Object o =null;
if(keys.length>0){
o = bundle.getObject(keys[0]);
o = findResource(o,keys,1);
}
o=resolveAliases(o,className,key,visited);
return o;
}
private Object resolveAliases(Object o,String className,String key, Hashtable visited){
if(o instanceof Object[][]){
o = resolveAliases((Object[][])o,className,key,visited);
}else if(o instanceof Object[]){
o = resolveAliases((Object[])o,className,key,visited);
}else if(o instanceof Alias){
return ((Alias)o).getResource(className,key,visited);
}
return o;
}
private Object resolveAliases(Object[][] o,String className, String key,Hashtable visited){
int i =0;
while(i<o.length){
o[i][1]=resolveAliases((Object)o[i][1],className,key,visited);
i++;
}
return o;
}
private Object resolveAliases(Object[] o,String className, String key,Hashtable visited){
int i =0;
while(i<o.length){
o[i]=resolveAliases((Object)o[i],className,key,visited);
i++;
}
return o;
}
private String[] split(String source, char delimiter){
char[] src = source.toCharArray();
int index = 0;
int numdelimit=0;
// first count the number of delimiters
for(int i=0;i<source.length();i++){
if(src[i]==delimiter){
numdelimit++;
}
}
String[] values =null;
values = new String[numdelimit+2];
// now split
int old=0;
for(int j=0;j<src.length;j++){
if(src[j]==delimiter){
values[index++] = new String(src,old,j-old);
old=j+1/* skip after the delimiter*/;
}
}
if(old <src.length)
values[index++]=new String(src,old,src.length-old);
return values;
}
}
}

View File

@ -4,18 +4,10 @@
package com.ibm.icu.impl;
import java.io.InputStream;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.jar.JarFile;
/**
* Provides information about and access to resource bundles in the
@ -134,6 +126,49 @@ public class ICULocaleData {
return null;
}
/**
* Get a resource bundle from the lookup chain.
*/
public static ResourceBundle getResourceBundle(String[] packages, String bundleName, String localeName) {
Locale locale = LocaleUtility.getLocaleFromName(localeName);
if (locale == null) {
locale = Locale.getDefault();
}
for (int i = 0; i < packages.length; ++i) {
try {
String path = packages[i] + "." + bundleName;
if (debug) System.out.println("calling instantiateBundle: " + path + "_" + locale);
ResourceBundle rb = instantiateBundle(path, locale);
return rb;
}
catch (MissingResourceException e) {
if (debug) System.out.println(bundleName + "_" + locale + " not found in " + packages[i]);
}
}
return null;
}
/**
* Get a resource bundle from the lookup chain.
*/
public static ResourceBundle getResourceBundle(String packageName, String bundleName, String localeName) {
Locale locale = LocaleUtility.getLocaleFromName(localeName);
if (locale == null) {
locale = Locale.getDefault();
}
try {
String path = packageName + "." + bundleName;
if (debug) System.out.println("calling instantiateBundle: " + path + "_" + locale);
ResourceBundle rb = instantiateBundle(path, locale);
return rb;
}
catch (MissingResourceException e) {
if (debug) System.out.println(bundleName + "_" + locale + " not found in " + packageName);
}
return null;
}
/**
* Get a resource bundle from the resource bundle path. Unlike getResourceBundle, this
* returns an 'unparented' bundle that exactly matches the bundle name and locale name.