1 8 package com.ibm.icu.impl; 9 10 import java.util.HashMap ; 11 import java.util.MissingResourceException ; 12 import java.util.ResourceBundle ; 13 14 import com.ibm.icu.util.StringTokenizer; 15 import com.ibm.icu.util.ULocale; 16 import com.ibm.icu.util.UResourceBundle; 17 import com.ibm.icu.util.UResourceTypeMismatchException; 18 19 23 26 public class ICUResourceBundleImpl extends ICUResourceBundle { 27 private byte[] rawData; 29 private long rootResource; 30 private boolean noFallback; 31 32 private String localeID; 33 private String baseName; 34 private ULocale ulocale; 35 private ClassLoader loader; 36 37 private static final boolean ASSERT = false; 38 39 46 public static ICUResourceBundle createBundle(String baseName, 47 String localeID, ClassLoader root) { 48 49 ICUResourceBundleReader reader = ICUResourceBundleReader.getReader( 50 baseName, localeID, root); 51 52 if (reader == null) { 54 return null; 55 } 56 57 ICUResourceBundleImpl bundle = new ICUResourceBundleImpl(reader, 58 baseName, localeID, root); 59 return bundle.getBundle(); 60 } 61 62 protected String getLocaleID() { 63 return localeID; 64 } 65 66 protected String getBaseName() { 67 return baseName; 68 } 69 70 public ULocale getULocale() { 71 return ulocale; 72 } 73 74 public UResourceBundle getParent() { 75 return (UResourceBundle) parent; 76 } 77 78 protected void setParent(ResourceBundle parent) { 79 this.parent = parent; 80 } 81 82 86 protected boolean getNoFallback() { 87 return noFallback; 88 } 89 90 private ICUResourceBundle getBundle() { 91 int type = RES_GET_TYPE(rootResource); 92 if (type == TABLE) { 93 ResourceTable table = new ResourceTable(null, rootResource, "", true); 94 if(table.size>=1){ ICUResourceBundle b = table.handleGet(0, table); 96 String itemKey = b.getKey(); 97 98 if (itemKey.equals("%%ALIAS")) { 100 String locale = b.getString(); 101 ICUResourceBundle actual = (ICUResourceBundle) UResourceBundle.getBundleInstance(baseName, locale); 102 return (ResourceTable) actual; 103 }else{ 104 return table; 105 } 106 }else { 107 return table; 108 } 109 } else if (type == TABLE32) { 110 111 return new ResourceTable32(null, rootResource, "", true); 113 } else { 114 throw new IllegalStateException ("Invalid format error"); 115 } 116 } 117 private ICUResourceBundleImpl(ICUResourceBundleReader reader, String baseName, 118 String localeID, ClassLoader loader) { 119 this.rawData = reader.getData(); 120 this.rootResource = (UNSIGNED_INT_MASK) & reader.getRootResource(); 121 this.noFallback = reader.getNoFallback(); 122 this.baseName = baseName; 123 this.localeID = localeID; 124 this.ulocale = new ULocale(localeID); 125 this.loader = loader; 126 } 127 static final int RES_GET_TYPE(long res) { 128 return (int) ((res) >> 28L); 129 } 130 private static final int RES_GET_OFFSET(long res) { 131 return (int) ((res & 0x0fffffff) * 4); 132 } 133 134 private static final int RES_GET_INT(long res) { 135 return (((int) ((res) << 4L)) >> 4L); 136 } 137 private static final long RES_GET_UINT(long res) { 138 long t = ((res) & 0x0fffffffL); 139 return t; 140 } 141 private static final StringBuffer RES_GET_KEY(byte[] rawData, 142 int keyOffset) { 143 char ch = 0xFFFF; StringBuffer key = new StringBuffer (); 145 while ((ch = (char) rawData[keyOffset]) != 0) { 146 key.append(ch); 147 keyOffset++; 148 } 149 return key; 150 } 151 private static final int getIntOffset(int offset) { 152 return (offset * 4); 153 } 154 private static final int getCharOffset(int offset) { 155 return (offset * 2); 156 } 157 private final ICUResourceBundle createBundleObject(String key, 158 long resource, String resPath, HashMap table, ICUResourceBundle requested) { 159 switch (RES_GET_TYPE(resource)) { 161 case STRING : { 162 return new ResourceString(key, resPath, resource); 163 } 164 case BINARY : { 165 return new ResourceBinary(key, resPath, resource); 166 } 167 case ALIAS : { 168 return findResource(key, resource, table, requested); 169 } 170 case INT : { 171 return new ResourceInt(key, resPath, resource); 172 } 173 case INT_VECTOR : { 174 return new ResourceIntVector(key, resPath, resource); 175 } 176 case ARRAY : { 177 return new ResourceArray(key, resPath, resource); 178 } 179 case TABLE32 : { 180 return new ResourceTable32(key, resPath, resource); 181 } 182 case TABLE : { 183 return new ResourceTable(key, resPath, resource); 184 } 185 default : 186 throw new IllegalStateException ("The resource type is unknown"); 187 } 188 } 191 private int findKey(int size, int currentOffset, Resource res, String target) { 192 int mid = 0, start = 0, limit = size, rc; 193 int lastMid = -1; 194 for (;;) { 196 mid = ((start + limit) / 2); 197 if (lastMid == mid) { 198 break; 199 } 200 lastMid = mid; 201 String comp = res.getKey(currentOffset, mid); 202 rc = target.compareTo(comp); 203 if (rc < 0) { 204 limit = mid; 205 } else if (rc > 0) { 206 start = mid; 207 } else { 208 return mid; 209 } 210 } 211 return -1; 212 } 213 private interface Resource { 214 public String getKey(int currentOfset, int index); 215 } 216 private class ResourceTable extends ICUResourceBundle implements Resource { 217 218 protected ICUResourceBundle handleGet(String key, ICUResourceBundle requested) { 219 return handleGet(key, null, requested); 220 } 221 protected ICUResourceBundle handleGet(String key, HashMap table, ICUResourceBundle requested) { 222 if(size<=0){ 223 return null; 224 } 225 int offset = RES_GET_OFFSET(resource); 226 int currentOffset = (offset) + getCharOffset(1); 229 231 int foundOffset = findKey(size, currentOffset, this, key); 232 if (foundOffset == -1) { 233 return null; 237 } 238 currentOffset += getCharOffset(size + (~size & 1)) 239 + getIntOffset(foundOffset); 240 long resource = (UNSIGNED_INT_MASK) & ICUResourceBundleImpl.getInt(rawData, currentOffset); 241 String path = (isTopLevel == true) ? key : resPath + "/" + key; 242 return createBundleObject(key, resource, path, table, requested); 243 } 244 protected ICUResourceBundle handleGet(int index, ICUResourceBundle requested) { 245 return handleGet(index, null, requested); 246 } 247 public String getKey(int currentOffset, int index) { 248 int charOffset = currentOffset + getCharOffset(index); 249 int keyOffset = getChar(rawData,charOffset); 250 return RES_GET_KEY(rawData, keyOffset).toString(); 251 } 252 protected ICUResourceBundle handleGet(int index, HashMap table, ICUResourceBundle requested) { 253 if (index > size) { 254 throw new IndexOutOfBoundsException (); 255 } 256 int offset = RES_GET_OFFSET(resource); 257 int currentOffset = (offset) + getCharOffset(1); 260 String itemKey = getKey(currentOffset, index); 261 currentOffset += getCharOffset(size + (~size & 1)) 262 + getIntOffset(index); 263 long resource = (UNSIGNED_INT_MASK) & ICUResourceBundleImpl.getInt(rawData,currentOffset); 264 String path = (isTopLevel == true) 265 ? Integer.toString(index) 266 : resPath + "/" + index; 267 return createBundleObject(itemKey, resource, path, table, requested); 268 } 269 private int countItems() { 270 int offset = RES_GET_OFFSET(resource); 271 int value = getChar(rawData,offset); 272 return value; 273 } 274 private ResourceTable(String key, String resPath, long resource) { 275 this(key, resource, resPath, false); 276 } 277 private ResourceTable(String key, long resource, String resPath, 278 boolean isTopLevel) { 279 this.key = key; 280 this.resource = resource; 281 this.isTopLevel = isTopLevel; 282 this.size = countItems(); 283 this.resPath = resPath; 284 } 285 protected String getLocaleID() { 286 return localeID; 287 } 288 protected String getBaseName() { 289 return baseName; 290 } 291 292 public ULocale getULocale() { 293 return ulocale; 294 } 295 public UResourceBundle getParent() { 296 return ICUResourceBundleImpl.this.getParent(); 297 } 298 protected void setParent(ResourceBundle parent) { 299 ICUResourceBundleImpl.this.setParent(parent); 300 } 301 } 302 private class ResourceTable32 extends ICUResourceBundle implements Resource { 303 304 protected ICUResourceBundle handleGet(String key, ICUResourceBundle requested) { 305 if(size<=0){ 306 return null; 307 } 308 return handleGet(key, null, requested); 309 } 310 protected ICUResourceBundle handleGet(String key, HashMap table, ICUResourceBundle requested) { 311 int offset = RES_GET_OFFSET(resource); 312 int currentOffset = (offset) + getIntOffset(1); 315 317 int foundOffset = findKey(size, currentOffset, this, key); 318 if (foundOffset == -1) { 319 throw new MissingResourceException ( 320 "Could not find resource ", 321 ICUResourceBundleReader.getFullName(baseName, localeID), 322 key); 323 } 324 currentOffset += getIntOffset(size) + getIntOffset(foundOffset); 325 long resource = (UNSIGNED_INT_MASK) & ICUResourceBundleImpl.getInt(rawData,currentOffset); 326 String path = (isTopLevel == true) ? key : resPath + "/" + key; 327 return createBundleObject(key, resource, path, table, requested); 328 } 329 protected ICUResourceBundle handleGet(int index, ICUResourceBundle requested) { 330 return handleGet(index, null, requested); 331 } 332 public String getKey(int currentOffset, int index) { 333 int charOffset = currentOffset + getIntOffset(index); 334 int keyOffset = ICUResourceBundleImpl.getInt(rawData,charOffset); 335 return RES_GET_KEY(rawData, keyOffset).toString(); 336 } 337 protected ICUResourceBundle handleGet(int index, HashMap table, ICUResourceBundle requested) { 338 if (index > size) { 339 throw new IndexOutOfBoundsException (); 340 } 341 int offset = RES_GET_OFFSET(resource); 342 int currentOffset = (offset) + getIntOffset(1) 345 + getIntOffset(index); 346 String itemKey = getKey(currentOffset, 0); 347 currentOffset += getIntOffset(size); 348 long resource = (UNSIGNED_INT_MASK) & ICUResourceBundleImpl.getInt(rawData,currentOffset); 349 String path = (isTopLevel == true) 350 ? Integer.toString(index) 351 : resPath + "/" + index; 352 return createBundleObject(itemKey, resource, path, table, requested); 353 } 354 private int countItems() { 355 int offset = RES_GET_OFFSET(resource); 356 int value = ICUResourceBundleImpl.getInt(rawData, offset); 357 return value; 358 } 359 private ResourceTable32(String key, long resource, String resPath, 360 boolean isTopLevel) { 361 this.resource = resource; 362 this.key = key; 363 this.isTopLevel = isTopLevel; 364 this.size = countItems(); 365 this.resPath = resPath; 366 } 367 private ResourceTable32(String key, String resPath, long resource) { 368 this(key, resource, resPath, false); 369 } 370 371 protected String getLocaleID() { 372 return localeID; 373 } 374 protected String getBaseName() { 375 return baseName; 376 } 377 378 public ULocale getULocale() { 379 return ulocale; 380 } 381 public UResourceBundle getParent() { 382 return ICUResourceBundleImpl.this.getParent(); 383 } 384 protected void setParent(ResourceBundle parent) { 385 ICUResourceBundleImpl.this.setParent(parent); 386 } 387 388 } 389 private class ResourceString extends ICUResourceBundle { 390 private String value; 391 public String getString() { 392 return value; 393 } 394 private ResourceString(String key, String resPath, long resource) { 395 value = getStringValue(resource); 396 this.key = key; 397 this.resource = resource; 398 this.resPath = resPath; 399 } 400 protected String getLocaleID() { 401 return localeID; 402 } 403 protected String getBaseName() { 404 return baseName; 405 } 406 407 public ULocale getULocale() { 408 return ulocale; 409 } 410 public UResourceBundle getParent() { 411 return ICUResourceBundleImpl.this.getParent(); 412 } 413 } 414 private class ResourceInt extends ICUResourceBundle { 415 public int getInt() { 416 return RES_GET_INT(resource); 417 } 418 public int getUInt() { 419 long ret = RES_GET_UINT(resource); 420 return (int) ret; 421 } 422 private ResourceInt(String key, String resPath, long resource) { 423 this.key = key; 424 this.resource = resource; 425 this.resPath = resPath; 426 } 427 protected String getLocaleID() { 428 return localeID; 429 } 430 protected String getBaseName() { 431 return baseName; 432 } 433 434 public ULocale getULocale() { 435 return ulocale; 436 } 437 public UResourceBundle getParent() { 438 return ICUResourceBundleImpl.this.getParent(); 439 } 440 } 441 private class ResourceArray extends ICUResourceBundle { 442 protected String [] handleGetStringArray() { 443 String [] strings = new String [size]; 444 ICUResourceBundleIterator iter = getIterator(); 445 int i = 0; 446 while (iter.hasNext()) { 447 strings[i++] = iter.next().getString(); 448 } 449 return strings; 450 } 451 454 public String [] getStringArray() { 455 return handleGetStringArray(); 456 } 457 protected ICUResourceBundle handleGet(String index, ICUResourceBundle requested) { 458 return handleGet(index, null, requested); 459 } 460 protected ICUResourceBundle handleGet(String index, HashMap table, ICUResourceBundle requested) { 461 int val = getIndex(index); 462 if (val > -1) { 463 return handleGet(val, table, requested); 464 } 465 throw new UResourceTypeMismatchException("Could not get the correct value for index: "+ index); 466 } 467 protected ICUResourceBundle handleGet(int index, ICUResourceBundle requested) { 468 return handleGet(index, null, requested); 469 } 470 protected ICUResourceBundle handleGet(int index, HashMap table, ICUResourceBundle requested) { 471 if (index > size) { 472 throw new IndexOutOfBoundsException (); 473 } 474 int offset = RES_GET_OFFSET(resource); 475 int itemOffset = offset + getIntOffset(index + 1); 476 long itemResource = (UNSIGNED_INT_MASK) & ICUResourceBundleImpl.getInt(rawData,itemOffset); 477 String path = (isTopLevel == true) ? Integer.toString(index) : resPath + "/" + index; 478 return createBundleObject(null, itemResource, path, table, requested); 479 } 480 private int countItems() { 481 int offset = RES_GET_OFFSET(resource); 482 int value = ICUResourceBundleImpl.getInt(rawData,offset); 483 return value; 484 } 485 private ResourceArray(String key, String resPath, long resource) { 486 this.resource = resource; 487 this.key = key; 488 this.size = countItems(); 489 this.resPath = resPath; 490 } 491 protected String getLocaleID() { 492 return localeID; 493 } 494 protected String getBaseName() { 495 return baseName; 496 } 497 498 public ULocale getULocale() { 499 return ulocale; 500 } 501 public UResourceBundle getParent() { 502 return ICUResourceBundleImpl.this.getParent(); 503 } 504 } 505 private static char makeChar(byte b1, byte b0) { 506 return (char)((b1 << 8) | (b0 & 0xff)); 507 } 508 private static char getChar(byte[]data, int offset){ 509 return makeChar(data[offset], data[offset+1]); 510 } 511 private static int makeInt(byte b3, byte b2, byte b1, byte b0) { 512 return (int)((((b3 & 0xff) << 24) | 513 ((b2 & 0xff) << 16) | 514 ((b1 & 0xff) << 8) | 515 ((b0 & 0xff) << 0))); 516 } 517 518 private static int getInt(byte[] data, int offset){ 519 if (ASSERT) Assert.assrt("offset < data.length", offset < data.length); 520 return makeInt(data[offset], data[offset+1], 521 data[offset+2], data[offset+3]); 522 } 523 524 private class ResourceBinary extends ICUResourceBundle { 525 private byte[] value; 526 public ByteBuffer getBinary() { 527 return ByteBuffer.wrap(value); 528 } 529 public byte [] getBinary(byte []ba) { 530 return value; 531 } 532 private byte[] getValue() { 533 int offset = RES_GET_OFFSET(resource); 534 int length = ICUResourceBundleImpl.getInt(rawData,offset); 535 int byteOffset = offset + getIntOffset(1); 536 byte[] dst = new byte[length]; 537 if (ASSERT) Assert.assrt("byteOffset+length < rawData.length", byteOffset+length < rawData.length); 538 System.arraycopy(rawData, byteOffset, dst, 0, length); 539 return dst; 540 } 541 public ResourceBinary(String key, String resPath, long resource) { 542 this.resource = resource; 543 this.key = key; 544 this.resPath = resPath; 545 value = getValue(); 546 } 547 protected String getLocaleID() { 548 return localeID; 549 } 550 protected String getBaseName() { 551 return baseName; 552 } 553 554 public ULocale getULocale() { 555 return ulocale; 556 } 557 public UResourceBundle getParent() { 558 return ICUResourceBundleImpl.this.getParent(); 559 } 560 } 561 private class ResourceIntVector extends ICUResourceBundle { 562 private int[] value; 563 public int[] getIntVector() { 564 return value; 565 } 566 private int[] getValue() { 567 int offset = RES_GET_OFFSET(resource); 568 int length = ICUResourceBundleImpl.getInt(rawData,offset); 569 int intOffset = offset + getIntOffset(1); 570 int[] val = new int[length]; 571 int byteLength = getIntOffset(length); 572 573 if (ASSERT) Assert.assrt("(intOffset+byteLength)<rawData.length", (intOffset+byteLength)<rawData.length); 574 575 for(int i=0; i<length;i++){ 576 val[i]=ICUResourceBundleImpl.getInt(rawData, intOffset+getIntOffset(i)); 577 } 578 return val; 579 } 580 public ResourceIntVector(String key, String resPath, long resource) { 581 this.key = key; 582 this.resource = resource; 583 this.size = 1; 584 this.resPath = resPath; 585 value = getValue(); 586 } 587 protected String getLocaleID() { 588 return localeID; 589 } 590 protected String getBaseName() { 591 return baseName; 592 } 593 594 public ULocale getULocale() { 595 return ulocale; 596 } 597 public UResourceBundle getParent() { 598 return ICUResourceBundleImpl.this.getParent(); 599 } 600 } 601 private String getStringValue(long resource) { 602 if (resource == 0) { 603 610 return ""; 611 } 612 int offset = RES_GET_OFFSET(resource); 613 int length = getInt(rawData,offset); 614 int stringOffset = offset + getIntOffset(1); 615 char[] dst = new char[length]; 616 if (ASSERT) Assert.assrt("(stringOffset+getCharOffset(length)) < rawData.length", (stringOffset+getCharOffset(length)) < rawData.length); 617 for(int i=0; i<length; i++){ 618 dst[i]=getChar(rawData, stringOffset+getCharOffset(i)); 619 } 620 return new String (dst); 621 } 622 private static final char RES_PATH_SEP_CHAR = '/'; 623 private static final String RES_PATH_SEP_STR = "/"; 624 private static final String ICUDATA = "ICUDATA"; 625 private static final char HYPHEN = '-'; 626 private static final String LOCALE = "LOCALE"; 627 628 private static final int getIndex(String s) { 629 if (s.length() >= 1) { 630 return Integer.valueOf(s).intValue(); 631 } 632 return -1; 633 } 634 private ICUResourceBundle findResource(String key, long resource, 635 HashMap table, 636 ICUResourceBundle requested) { 637 ClassLoader loaderToUse = loader; 638 String locale = null, keyPath = null; 639 String bundleName; 640 String resPath = getStringValue(resource); 641 if (table == null) { 642 table = new HashMap (); 643 } 644 if (table.get(resPath) != null) { 645 throw new IllegalArgumentException ( 646 "Circular references in the resource bundles"); 647 } 648 table.put(resPath, ""); 649 if (resPath.indexOf(RES_PATH_SEP_CHAR) == 0) { 650 int i = resPath.indexOf(RES_PATH_SEP_CHAR, 1); 651 int j = resPath.indexOf(RES_PATH_SEP_CHAR, i + 1); 652 bundleName = resPath.substring(1, i); 653 locale = resPath.substring(i + 1); 654 if (j != -1) { 655 locale = resPath.substring(i + 1, j); 656 keyPath = resPath.substring(j + 1, resPath.length()); 657 } 658 if (bundleName.equals(ICUDATA)) { 660 bundleName = ICU_BASE_NAME; 661 loaderToUse = ICU_DATA_CLASS_LOADER; 662 }else if(bundleName.indexOf(ICUDATA)>-1){ 663 int idx = bundleName.indexOf(HYPHEN); 664 if(idx>-1){ 665 bundleName = ICU_BASE_NAME+RES_PATH_SEP_STR+bundleName.substring(idx+1,bundleName.length()); 666 loaderToUse = ICU_DATA_CLASS_LOADER; 667 } 668 } 669 } else { 670 int i = resPath.indexOf(RES_PATH_SEP_CHAR); 672 keyPath = resPath.substring(i + 1); 673 if (i != -1) { 674 locale = resPath.substring(0, i); 675 } else { 676 locale = keyPath; 677 keyPath = null; } 679 bundleName = baseName; 680 } 681 ICUResourceBundle bundle = null; 682 ICUResourceBundle sub = null; 683 if(bundleName.equals(LOCALE)){ 684 bundleName = baseName; 685 bundle = requested; 686 keyPath = resPath.substring(LOCALE.length() + 2, resPath.length()); 687 locale = requested.getLocaleID(); 688 sub = ICUResourceBundle.findResourceWithFallback(keyPath, requested, null); 689 sub.resPath = "/" + sub.getLocaleID() + "/" + keyPath; 690 }else{ 691 if (locale == null) { 692 bundle = (ICUResourceBundle) getBundleInstance(bundleName, "", 694 loaderToUse, false); 695 } else { 696 bundle = (ICUResourceBundle) getBundleInstance(bundleName, locale, 697 loaderToUse, false); 698 } 699 if (keyPath != null) { 700 StringTokenizer st = new StringTokenizer(keyPath, "/"); 701 ICUResourceBundle current = bundle; 702 while (st.hasMoreTokens()) { 703 String subKey = st.nextToken(); 704 sub = current.getImpl(subKey, table, requested); 705 if (sub == null) { 706 break; 707 } 708 current = sub; 709 } 710 } else { 711 sub = bundle.get(key); 715 } 716 sub.resPath = resPath; 717 } 718 if (sub == null) { 719 throw new MissingResourceException (localeID, baseName, key); 720 } 721 return sub; 722 } 723 } 724 725 | Popular Tags |