blob: f5b3604bf2a6f49446942838457a437fe1a1c15c [file] [log] [blame]
/**
*******************************************************************************
* Copyright (C) 2001-2002, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/impl/ICUListResourceBundle.java,v $
* $Date: 2002/08/13 23:40:52 $
* $Revision: 1.9 $
*
*******************************************************************************
*/
/**
* A list resource bundle that does redirection
* because otherwise some of our resource class files
* are too big for the java runtime to handle.
*/
package com.ibm.icu.impl;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.ListResourceBundle;
import java.util.ResourceBundle;
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() {
}
private Hashtable visited = new Hashtable();
/**
* Subclassers must statically initialize this
*/
protected Object[][] contents;
/**
* This is our cache
*/
private Object[][] realContents;
/**
* 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 = getRedirectedResource((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 };
}
}
}
return realContents;
}
/**
* Return null if value is already in existing contents array, otherwise fetch the
* real value and return it.
*/
private Object getRedirectedResource(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] = getRedirectedResource((String)aValue[i][0],aValue[i][j]);
j++;
}
i++;
}
}else if(value instanceof Alias){
String cName = this.getClass().getName();
visited.clear();
visited.put(cName+key,"");
return ((Alias)value).getResource(cName,key,visited);
}else if(value instanceof RedirectedResource){
return ((RedirectedResource)value).getResource(this);
}
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 {
do {
int n = stream.read(buffer, pos, length - pos);
if (n == -1) {
break;
}
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;
}
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 {
do {
int n = stream.read(buffer, pos, length - pos);
if (n == -1) {
break;
}
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;
}
/*
public static class CompressedString implements RedirectedResource{
private String expanded=null;
private String compressed=null;
public CompressedString(String str){
compressed=str;
}
public Object getResource(Object obj){
if(compressed==null){
return null;
}
if(expanded==null){
expanded= new String(Utility.RLEStringToCharArray(compressed));
}
return expanded;
}
}
*/
public static class CompressedBinary implements RedirectedResource{
private byte[] expanded=null;
private String compressed=null;
public CompressedBinary(String str){
compressed = str;
}
public Object getResource(Object obj){
if(compressed==null){
return null;
}
if(expanded==null){
expanded= Utility.RLEStringToByteArray(compressed);
}
return expanded;
}
}
private interface RedirectedResource{
public Object getResource(Object obj);
}
public static class ResourceBinary implements RedirectedResource{
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 implements RedirectedResource{
private char[] expanded=null;
private String resName=null;
public ResourceString(String name){
resName=name;
}
public Object getResource(Object obj){
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);
}
try{
InputStreamReader reader = new InputStreamReader(stream,ENCODING);
expanded = readToEOS(reader);
}catch(UnsupportedEncodingException ex){
throw new RuntimeException("Could open converter for encoding: " +ENCODING);
}
}
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;
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;
}
}
}