1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2004-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.impl; 10 11 import java.nio.ByteBuffer; 12 import java.util.HashMap; 13 import java.util.Set; 14 import java.util.TreeSet; 15 16 import com.ibm.icu.util.UResourceBundle; 17 import com.ibm.icu.util.UResourceTypeMismatchException; 18 19 class ICUResourceBundleImpl extends ICUResourceBundle { 20 protected int resource; 21 ICUResourceBundleImpl(ICUResourceBundleImpl container, String key, int resource)22 protected ICUResourceBundleImpl(ICUResourceBundleImpl container, String key, int resource) { 23 super(container, key); 24 this.resource = resource; 25 } ICUResourceBundleImpl(WholeBundle wholeBundle)26 ICUResourceBundleImpl(WholeBundle wholeBundle) { 27 super(wholeBundle); 28 resource = wholeBundle.reader.getRootResource(); 29 } getResource()30 public int getResource() { 31 return resource; 32 } createBundleObject(String _key, int _resource, HashMap<String, String> aliasesVisited, UResourceBundle requested)33 protected final ICUResourceBundle createBundleObject(String _key, 34 int _resource, 35 HashMap<String, String> aliasesVisited, 36 UResourceBundle requested) { 37 switch(ICUResourceBundleReader.RES_GET_TYPE(_resource)) { 38 case STRING : 39 case STRING_V2: 40 return new ICUResourceBundleImpl.ResourceString(this, _key, _resource); 41 case BINARY: 42 return new ICUResourceBundleImpl.ResourceBinary(this, _key, _resource); 43 case ALIAS: 44 return getAliasedResource(this, null, 0, _key, _resource, aliasesVisited, requested); 45 case INT: 46 return new ICUResourceBundleImpl.ResourceInt(this, _key, _resource); 47 case INT_VECTOR: 48 return new ICUResourceBundleImpl.ResourceIntVector(this, _key, _resource); 49 case ARRAY: 50 case ARRAY16: 51 return new ICUResourceBundleImpl.ResourceArray(this, _key, _resource); 52 case TABLE: 53 case TABLE16: 54 case TABLE32: 55 return new ICUResourceBundleImpl.ResourceTable(this, _key, _resource); 56 default : 57 throw new IllegalStateException("The resource type is unknown"); 58 } 59 } 60 61 // Scalar values ------------------------------------------------------- *** 62 63 private static final class ResourceBinary extends ICUResourceBundleImpl { 64 @Override getType()65 public int getType() { 66 return BINARY; 67 } 68 @Override getBinary()69 public ByteBuffer getBinary() { 70 return wholeBundle.reader.getBinary(resource); 71 } 72 @Override getBinary(byte []ba)73 public byte [] getBinary(byte []ba) { 74 return wholeBundle.reader.getBinary(resource, ba); 75 } ResourceBinary(ICUResourceBundleImpl container, String key, int resource)76 ResourceBinary(ICUResourceBundleImpl container, String key, int resource) { 77 super(container, key, resource); 78 } 79 } 80 private static final class ResourceInt extends ICUResourceBundleImpl { 81 @Override getType()82 public int getType() { 83 return INT; 84 } 85 @Override getInt()86 public int getInt() { 87 return ICUResourceBundleReader.RES_GET_INT(resource); 88 } 89 @Override getUInt()90 public int getUInt() { 91 return ICUResourceBundleReader.RES_GET_UINT(resource); 92 } ResourceInt(ICUResourceBundleImpl container, String key, int resource)93 ResourceInt(ICUResourceBundleImpl container, String key, int resource) { 94 super(container, key, resource); 95 } 96 } 97 private static final class ResourceString extends ICUResourceBundleImpl { 98 private String value; 99 @Override getType()100 public int getType() { 101 return STRING; 102 } 103 @Override getString()104 public String getString() { 105 if (value != null) { 106 return value; 107 } 108 return wholeBundle.reader.getString(resource); 109 } ResourceString(ICUResourceBundleImpl container, String key, int resource)110 ResourceString(ICUResourceBundleImpl container, String key, int resource) { 111 super(container, key, resource); 112 String s = wholeBundle.reader.getString(resource); 113 // Allow the reader cache's SoftReference to do its job. 114 if (s.length() < ICUResourceBundleReader.LARGE_SIZE / 2 || 115 CacheValue.futureInstancesWillBeStrong()) { 116 value = s; 117 } 118 } 119 } 120 private static final class ResourceIntVector extends ICUResourceBundleImpl { 121 @Override getType()122 public int getType() { 123 return INT_VECTOR; 124 } 125 @Override getIntVector()126 public int[] getIntVector() { 127 return wholeBundle.reader.getIntVector(resource); 128 } ResourceIntVector(ICUResourceBundleImpl container, String key, int resource)129 ResourceIntVector(ICUResourceBundleImpl container, String key, int resource) { 130 super(container, key, resource); 131 } 132 } 133 134 // Container values ---------------------------------------------------- *** 135 136 static abstract class ResourceContainer extends ICUResourceBundleImpl { 137 protected ICUResourceBundleReader.Container value; 138 139 @Override getSize()140 public int getSize() { 141 return value.getSize(); 142 } 143 @Override getString(int index)144 public String getString(int index) { 145 int res = value.getContainerResource(wholeBundle.reader, index); 146 if (res == RES_BOGUS) { 147 throw new IndexOutOfBoundsException(); 148 } 149 String s = wholeBundle.reader.getString(res); 150 if (s != null) { 151 return s; 152 } 153 return super.getString(index); 154 } getContainerResource(int index)155 protected int getContainerResource(int index) { 156 return value.getContainerResource(wholeBundle.reader, index); 157 } createBundleObject(int index, String resKey, HashMap<String, String> aliasesVisited, UResourceBundle requested)158 protected UResourceBundle createBundleObject(int index, String resKey, HashMap<String, String> aliasesVisited, 159 UResourceBundle requested) { 160 int item = getContainerResource(index); 161 if (item == RES_BOGUS) { 162 throw new IndexOutOfBoundsException(); 163 } 164 return createBundleObject(resKey, item, aliasesVisited, requested); 165 } 166 ResourceContainer(ICUResourceBundleImpl container, String key, int resource)167 ResourceContainer(ICUResourceBundleImpl container, String key, int resource) { 168 super(container, key, resource); 169 } ResourceContainer(WholeBundle wholeBundle)170 ResourceContainer(WholeBundle wholeBundle) { 171 super(wholeBundle); 172 } 173 } 174 static class ResourceArray extends ResourceContainer { 175 @Override getType()176 public int getType() { 177 return ARRAY; 178 } 179 @Override handleGetStringArray()180 protected String[] handleGetStringArray() { 181 ICUResourceBundleReader reader = wholeBundle.reader; 182 int length = value.getSize(); 183 String[] strings = new String[length]; 184 for (int i = 0; i < length; ++i) { 185 String s = reader.getString(value.getContainerResource(reader, i)); 186 if (s == null) { 187 throw new UResourceTypeMismatchException(""); 188 } 189 strings[i] = s; 190 } 191 return strings; 192 } 193 @Override getStringArray()194 public String[] getStringArray() { 195 return handleGetStringArray(); 196 } 197 @Override handleGet(String indexStr, HashMap<String, String> aliasesVisited, UResourceBundle requested)198 protected UResourceBundle handleGet(String indexStr, HashMap<String, String> aliasesVisited, 199 UResourceBundle requested) { 200 int i = Integer.parseInt(indexStr); 201 return createBundleObject(i, indexStr, aliasesVisited, requested); 202 } 203 @Override handleGet(int index, HashMap<String, String> aliasesVisited, UResourceBundle requested)204 protected UResourceBundle handleGet(int index, HashMap<String, String> aliasesVisited, 205 UResourceBundle requested) { 206 return createBundleObject(index, Integer.toString(index), aliasesVisited, requested); 207 } ResourceArray(ICUResourceBundleImpl container, String key, int resource)208 ResourceArray(ICUResourceBundleImpl container, String key, int resource) { 209 super(container, key, resource); 210 value = wholeBundle.reader.getArray(resource); 211 } 212 } 213 static class ResourceTable extends ResourceContainer { 214 @Override getType()215 public int getType() { 216 return TABLE; 217 } getKey(int index)218 protected String getKey(int index) { 219 return ((ICUResourceBundleReader.Table)value).getKey(wholeBundle.reader, index); 220 } 221 @Override handleKeySet()222 protected Set<String> handleKeySet() { 223 ICUResourceBundleReader reader = wholeBundle.reader; 224 TreeSet<String> keySet = new TreeSet<String>(); 225 ICUResourceBundleReader.Table table = (ICUResourceBundleReader.Table)value; 226 for (int i = 0; i < table.getSize(); ++i) { 227 keySet.add(table.getKey(reader, i)); 228 } 229 return keySet; 230 } 231 @Override handleGet(String resKey, HashMap<String, String> aliasesVisited, UResourceBundle requested)232 protected UResourceBundle handleGet(String resKey, HashMap<String, String> aliasesVisited, 233 UResourceBundle requested) { 234 int i = ((ICUResourceBundleReader.Table)value).findTableItem(wholeBundle.reader, resKey); 235 if (i < 0) { 236 return null; 237 } 238 return createBundleObject(resKey, getContainerResource(i), aliasesVisited, requested); 239 } 240 @Override handleGet(int index, HashMap<String, String> aliasesVisited, UResourceBundle requested)241 protected UResourceBundle handleGet(int index, HashMap<String, String> aliasesVisited, 242 UResourceBundle requested) { 243 String itemKey = ((ICUResourceBundleReader.Table)value).getKey(wholeBundle.reader, index); 244 if (itemKey == null) { 245 throw new IndexOutOfBoundsException(); 246 } 247 return createBundleObject(itemKey, getContainerResource(index), aliasesVisited, requested); 248 } 249 @Override handleGetObject(String key)250 protected Object handleGetObject(String key) { 251 // Fast path for common cases: Avoid creating UResourceBundles if possible. 252 // It would be even better if we could override getString(key)/getStringArray(key), 253 // so that we know the expected object type, 254 // but those are final in java.util.ResourceBundle. 255 ICUResourceBundleReader reader = wholeBundle.reader; 256 int index = ((ICUResourceBundleReader.Table)value).findTableItem(reader, key); 257 if (index >= 0) { 258 int res = value.getContainerResource(reader, index); 259 // getString(key) 260 String s = reader.getString(res); 261 if (s != null) { 262 return s; 263 } 264 // getStringArray(key) 265 ICUResourceBundleReader.Container array = reader.getArray(res); 266 if (array != null) { 267 int length = array.getSize(); 268 String[] strings = new String[length]; 269 for (int j = 0;; ++j) { 270 if (j == length) { 271 return strings; 272 } 273 s = reader.getString(array.getContainerResource(reader, j)); 274 if (s == null) { 275 // Equivalent to resolveObject(key, requested): 276 // If this is not a string array, 277 // then build and return a UResourceBundle. 278 break; 279 } 280 strings[j] = s; 281 } 282 } 283 } 284 return super.handleGetObject(key); 285 } 286 /** 287 * Returns a String if found, or null if not found or if the key item is not a string. 288 */ findString(String key)289 String findString(String key) { 290 ICUResourceBundleReader reader = wholeBundle.reader; 291 int index = ((ICUResourceBundleReader.Table)value).findTableItem(reader, key); 292 if (index < 0) { 293 return null; 294 } 295 return reader.getString(value.getContainerResource(reader, index)); 296 } ResourceTable(ICUResourceBundleImpl container, String key, int resource)297 ResourceTable(ICUResourceBundleImpl container, String key, int resource) { 298 super(container, key, resource); 299 value = wholeBundle.reader.getTable(resource); 300 } 301 /** 302 * Constructor for the root table of a bundle. 303 */ ResourceTable(WholeBundle wholeBundle, int rootRes)304 ResourceTable(WholeBundle wholeBundle, int rootRes) { 305 super(wholeBundle); 306 value = wholeBundle.reader.getTable(rootRes); 307 } 308 } 309 } 310