1 package net.sf.saxon.om; 2 3 import net.sf.saxon.style.StandardNames; 4 import net.sf.saxon.trans.DynamicError; 5 6 import java.io.Serializable ; 7 import java.util.HashMap ; 8 import java.util.StringTokenizer ; 9 10 24 25 public class NamePool implements Serializable { 26 27 53 62 63 public static final int FP_MASK = 0xfffff; 64 65 66 69 private static NamePool defaultNamePool = new NamePool(); 70 71 74 75 public static NamePool getDefaultNamePool() { 76 return defaultNamePool; 77 } 78 79 83 84 public static void setDefaultNamePool(NamePool pool) { 85 defaultNamePool = pool; 86 } 87 88 89 private static class NameEntry implements Serializable { 90 String localName; 91 short uriCode; 92 NameEntry nextEntry; 94 public NameEntry(short uriCode, String localName) { 95 this.uriCode = uriCode; 96 this.localName = localName.intern(); 97 this.nextEntry = null; 98 } 99 100 } 101 102 NameEntry[] hashslots = new NameEntry[1024]; 103 104 String [] prefixes = new String [100]; 105 short prefixesUsed = 0; 106 String [] uris = new String [100]; 107 String [] prefixesForUri = new String [100]; 108 short urisUsed = 0; 109 110 112 private HashMap clientData; 113 114 public NamePool() { 115 116 prefixes[NamespaceConstant.NULL_CODE] = ""; 117 uris[NamespaceConstant.NULL_CODE] = NamespaceConstant.NULL; 118 prefixesForUri[NamespaceConstant.NULL_CODE] = ""; 119 120 prefixes[NamespaceConstant.XML_CODE] = "xml"; 121 uris[NamespaceConstant.XML_CODE] = NamespaceConstant.XML; 122 prefixesForUri[NamespaceConstant.XML_CODE] = "xml "; 123 124 prefixes[NamespaceConstant.XSLT_CODE] = "xsl"; 125 uris[NamespaceConstant.XSLT_CODE] = NamespaceConstant.XSLT; 126 prefixesForUri[NamespaceConstant.XSLT_CODE] = "xsl "; 127 128 prefixes[NamespaceConstant.SAXON_CODE] = "saxon"; 129 uris[NamespaceConstant.SAXON_CODE] = NamespaceConstant.SAXON; 130 prefixesForUri[NamespaceConstant.SAXON_CODE] = "saxon "; 131 132 prefixes[NamespaceConstant.SCHEMA_CODE] = "xs"; 133 uris[NamespaceConstant.SCHEMA_CODE] = NamespaceConstant.SCHEMA; 134 prefixesForUri[NamespaceConstant.SCHEMA_CODE] = "xs "; 135 136 prefixes[NamespaceConstant.XDT_CODE] = "xdt"; 137 uris[NamespaceConstant.XDT_CODE] = NamespaceConstant.XDT; 138 prefixesForUri[NamespaceConstant.XDT_CODE] = "xdt "; 139 140 prefixes[NamespaceConstant.XSI_CODE] = "xsi"; 141 uris[NamespaceConstant.XSI_CODE] = NamespaceConstant.SCHEMA_INSTANCE; 142 prefixesForUri[NamespaceConstant.XSI_CODE] = "xsi "; 143 144 prefixesUsed = 7; 145 urisUsed = 7; 146 147 } 148 149 154 155 private NameEntry getNameEntry(int nameCode) { 156 int hash = nameCode & 0x3ff; 157 int depth = (nameCode >> 10) & 0x3ff; 158 NameEntry entry = hashslots[hash]; 159 160 for (int i = 1; i < depth; i++) { 161 if (entry == null) { 162 return null; 163 } 164 entry = entry.nextEntry; 165 } 166 return entry; 167 } 168 169 178 179 public synchronized int allocateNamespaceCode(String prefix, String uri) { 180 182 int prefixCode = allocateCodeForPrefix(prefix); 183 int uriCode = allocateCodeForURI(uri); 184 185 if (prefixCode != 0) { 186 String key = prefix + ' '; 188 if (prefixesForUri[uriCode].indexOf(key) < 0) { 189 prefixesForUri[uriCode] += key; 190 } 191 } 192 193 return (prefixCode << 16) + uriCode; 194 } 195 196 201 202 public int getNamespaceCode(String prefix, String uri) { 203 int prefixCode = getCodeForPrefix(prefix); 205 if (prefixCode < 0) { 206 return -1; 207 } 208 int uriCode = getCodeForURI(uri); 209 if (uriCode < 0) { 210 return -1; 211 } 212 213 if (prefixCode != 0) { 214 String key = prefix + ' '; 216 if (prefixesForUri[uriCode].indexOf(key) < 0) { 217 return -1; 218 } 219 } 220 221 return (prefixCode << 16) + uriCode; 222 } 223 224 232 233 public int getNamespaceCode(int namecode) { 234 short uriCode; 235 int fp = namecode & 0xfffff; 236 if ((fp & 0xffc00) == 0) { 237 uriCode = StandardNames.getURICode(fp); 238 } else { 239 NameEntry entry = getNameEntry(namecode); 240 if (entry == null) { 241 return -1; 242 } else { 243 uriCode = entry.uriCode; 244 } 245 } 246 int prefixIndex = (namecode >> 20) & 0xff; 247 String prefix = getPrefixWithIndex(uriCode, prefixIndex); 248 if (prefix == null) { 249 return -1; 250 } 251 int prefixCode = getCodeForPrefix(prefix); 252 if (prefixCode == -1) { 253 return -1; 254 } 255 return (prefixCode << 16) + uriCode; 256 } 257 258 259 263 264 public synchronized short allocateCodeForURI(String uri) { 265 for (short j = 0; j < urisUsed; j++) { 267 if (uris[j].equals(uri)) { 268 return j; 269 } 270 } 271 if (urisUsed >= uris.length) { 272 if (urisUsed > 32000) { 273 throw new NamePoolLimitException("Too many namespace URIs"); 274 } 275 String [] p = new String [urisUsed * 2]; 276 String [] u = new String [urisUsed * 2]; 277 System.arraycopy(prefixesForUri, 0, p, 0, urisUsed); 278 System.arraycopy(uris, 0, u, 0, urisUsed); 279 prefixesForUri = p; 280 uris = u; 281 } 282 uris[urisUsed] = uri; 283 prefixesForUri[urisUsed] = ""; 284 return urisUsed++; 285 } 286 287 288 293 294 public short getCodeForURI(String uri) { 295 for (short j = 0; j < urisUsed; j++) { 296 if (uris[j].equals(uri)) { 297 return j; 298 } 299 } 300 return -1; 301 } 302 303 309 310 private short allocateCodeForPrefix(String prefix) { 311 313 short start = 1; 315 if (prefix.equals("")) { 316 return NamespaceConstant.NULL_CODE; 317 } 318 if (prefix.charAt(0) != 'x') { 319 if (prefix.equals("saxon")) { 320 return NamespaceConstant.SAXON_CODE; 321 } 322 start = NamespaceConstant.XSI_CODE + 1; 323 } 324 325 for (short i=start; i < prefixesUsed; i++) { 326 if (prefixes[i].equals(prefix)) { 327 return i; 328 } 329 } 330 if (prefixesUsed >= prefixes.length) { 331 if (prefixesUsed > 32000) { 332 throw new NamePoolLimitException("Too many namespace prefixes"); 333 } 334 String [] p = new String [prefixesUsed * 2]; 335 System.arraycopy(prefixes, 0, p, 0, prefixesUsed); 336 prefixes = p; 337 } 338 prefixes[prefixesUsed] = prefix; 339 return prefixesUsed++; 340 } 341 342 343 348 349 public short getCodeForPrefix(String prefix) { 350 for (short i = 0; i < prefixesUsed; i++) { 351 if (prefixes[i].equals(prefix)) { 352 return i; 353 } 354 } 355 return -1; 356 } 357 358 362 363 public String suggestPrefixForURI(String URI) { 364 short uriCode = getCodeForURI(URI); 365 if (uriCode == -1) { 366 return null; 367 } 368 StringTokenizer tok = new StringTokenizer (prefixesForUri[uriCode]); 369 if (tok.hasMoreElements()) { 370 return (String )tok.nextElement(); 371 } 372 return null; 373 } 374 375 380 381 private int getPrefixIndex(short uriCode, String prefix) { 382 383 if (prefix.equals("")) { 385 return 0; 386 } 387 if (prefixesForUri[uriCode].equals(prefix + ' ')) { 388 return 1; 389 } 390 391 int i = 1; 393 StringTokenizer tok = new StringTokenizer (prefixesForUri[uriCode]); 394 while (tok.hasMoreElements()) { 395 if (prefix.equals(tok.nextElement())) { 396 return i; 397 } 398 if (i++ == 255) { 399 throw new NamePoolLimitException("Too many prefixes for one namespace URI"); 400 } 401 } 402 return -1; 403 } 404 405 410 411 public String getPrefixWithIndex(short uriCode, int index) { 412 if (index == 0) { 413 return ""; 414 } 415 StringTokenizer tok = new StringTokenizer (prefixesForUri[uriCode]); 416 int i = 1; 417 while (tok.hasMoreElements()) { 418 String prefix = (String )tok.nextElement(); 419 if (i++ == index) { 420 return prefix; 421 } 422 } 423 return null; 424 } 425 426 435 436 public synchronized int allocate(String prefix, String uri, String localName) { 437 if (NamespaceConstant.isReserved(uri) || uri.equals(NamespaceConstant.SAXON)) { 438 int fp = StandardNames.getFingerprint(uri, localName); 439 if (fp != -1) { 440 short uriCode = StandardNames.getURICode(fp); 441 int prefixIndex = getPrefixIndex(uriCode, prefix); 442 443 if (prefixIndex < 0) { 444 prefixesForUri[uriCode] += (prefix + ' '); 445 prefixIndex = getPrefixIndex(uriCode, prefix); 446 } 447 448 return (prefixIndex << 20) + fp; 449 } 450 } 451 short uriCode = allocateCodeForURI(uri); 453 return allocate(prefix, uriCode, localName); 454 } 455 456 464 465 public synchronized int allocate(String prefix, short uriCode, String localName) { 466 int hash = (localName.hashCode() & 0x7fffffff) % 1023; 468 int depth = 1; 469 int prefixIndex = getPrefixIndex(uriCode, prefix); 470 471 if (prefixIndex < 0) { 472 prefixesForUri[uriCode] += (prefix + ' '); 473 prefixIndex = getPrefixIndex(uriCode, prefix); 474 } 475 NameEntry entry; 476 477 if (hashslots[hash] == null) { 478 entry = new NameEntry(uriCode, localName); 479 hashslots[hash] = entry; 480 } else { 481 entry = hashslots[hash]; 482 while (true) { 483 boolean sameLocalName = (entry.localName.equals(localName)); 484 boolean sameURI = (entry.uriCode == uriCode); 485 486 if (sameLocalName && sameURI) { 487 break; 489 } else { 490 NameEntry next = entry.nextEntry; 491 depth++; 492 if (depth >= 1024) { 493 throw new NamePoolLimitException("Saxon name pool is full"); 494 } 495 if (next == null) { 496 NameEntry newentry = new NameEntry(uriCode, localName); 497 entry.nextEntry = newentry; 498 break; 499 } else { 500 entry = next; 501 } 502 } 503 } 504 } 505 return ((prefixIndex << 20) + (depth << 10) + hash); 507 } 508 509 516 517 public synchronized int allocateNamespaceCode(int namecode) { 518 short uriCode; 519 int fp = namecode & 0xfffff; 520 if ((fp & 0xffc00) == 0) { 521 uriCode = StandardNames.getURICode(fp); 522 } else { 523 NameEntry entry = getNameEntry(namecode); 524 if (entry == null) { 525 unknownNameCode(namecode); 526 return -1; } else { 528 uriCode = entry.uriCode; 529 } 530 } 531 int prefixIndex = (namecode >> 20) & 0xff; 532 String prefix = getPrefixWithIndex(uriCode, prefixIndex); 533 int prefixCode = allocateCodeForPrefix(prefix); 534 return (prefixCode << 16) + uriCode; 535 } 536 537 540 541 public String getURI(int nameCode) { 542 if ((nameCode & 0xffc00) == 0) { 543 return StandardNames.getURI(nameCode & 0xfffff); 544 } 545 NameEntry entry = getNameEntry(nameCode); 546 if (entry == null) { 547 unknownNameCode(nameCode); 548 return null; } 550 return uris[entry.uriCode]; 551 } 552 553 556 557 public short getURICode(int nameCode) { 558 if ((nameCode & 0xffc00) == 0) { 559 return StandardNames.getURICode(nameCode & 0xfffff); 560 } 561 NameEntry entry = getNameEntry(nameCode); 562 if (entry == null) { 563 unknownNameCode(nameCode); 564 return -1; 565 } 566 return entry.uriCode; 567 } 568 569 572 573 public String getLocalName(int nameCode) { 574 if ((nameCode & 0xffc00) == 0) { 575 return StandardNames.getLocalName(nameCode & 0xfffff); 576 } 577 NameEntry entry = getNameEntry(nameCode); 578 if (entry == null) { 579 unknownNameCode(nameCode); 580 return null; 581 } 582 return entry.localName; 583 } 584 585 588 589 public String getPrefix(int nameCode) { 590 if ((nameCode & 0xffc00) == 0) { 591 return StandardNames.getPrefix(nameCode & 0xfffff); 592 } 593 short uriCode = getURICode(nameCode); 594 int prefixIndex = (nameCode >> 20) & 0xff; 595 return getPrefixWithIndex(uriCode, prefixIndex); 596 } 597 598 601 602 public String getDisplayName(int nameCode) { 603 if ((nameCode & 0xffc00) == 0) { 604 int prefixIndex = (nameCode >> 20) & 0xff; 606 short uriCode = getURICode(nameCode); 607 String prefix = getPrefixWithIndex(uriCode, prefixIndex); 608 if (prefix.equals("")) { 609 return StandardNames.getLocalName(nameCode & 0xfffff); 610 } else { 611 return prefix + ':' + StandardNames.getLocalName(nameCode & 0xfffff); 612 } 613 } 614 615 NameEntry entry = getNameEntry(nameCode); 616 if (entry == null) { 617 unknownNameCode(nameCode); 618 return null; 619 } 620 int prefixIndex = (nameCode >> 20) & 0xff; 621 String prefix = getPrefixWithIndex(entry.uriCode, prefixIndex); 622 if (prefix == null || prefix.equals("")) { 623 return entry.localName; 624 } else { 625 return prefix + ':' + entry.localName; 626 } 627 } 628 629 635 636 public String getClarkName(int nameCode) { 637 if ((nameCode & 0xffc00) == 0) { 638 return StandardNames.getClarkName(nameCode & 0xfffff); 639 } 640 NameEntry entry = getNameEntry(nameCode); 641 if (entry == null) { 642 unknownNameCode(nameCode); 643 return null; 644 } 645 if (entry.uriCode == 0) { 646 return entry.localName; 647 } else { 648 String n = 649 '{' + getURIFromURICode(entry.uriCode) + '}' + entry.localName; 650 return n.intern(); 651 } 652 } 653 654 657 658 public int allocateClarkName(String expandedName) { 659 String namespace; 660 String localName; 661 if (expandedName.charAt(0) == '{') { 662 int closeBrace = expandedName.indexOf('}'); 663 if (closeBrace < 0) { 664 throw new IllegalArgumentException ("No closing '}' in Clark name"); 665 } 666 namespace = expandedName.substring(1, closeBrace); 667 if (closeBrace == expandedName.length()) { 668 throw new IllegalArgumentException ("Missing local part in Clark name"); 669 } 670 localName = expandedName.substring(closeBrace + 1); 671 } else { 672 namespace = ""; 673 localName = expandedName; 674 } 675 676 return allocate("", namespace, localName); 677 } 678 679 680 685 686 private void unknownNameCode(int nameCode) { 687 throw new IllegalArgumentException ("Unknown name code " + nameCode); 691 } 692 693 701 702 public int getFingerprint(String uri, String localName) { 703 705 short uriCode; 706 if (uri.equals("")) { 707 uriCode = 0; 708 } else { 709 if (NamespaceConstant.isReserved(uri) || uri.equals(NamespaceConstant.SAXON)) { 710 int fp = StandardNames.getFingerprint(uri, localName); 711 if (fp != -1) { 712 return fp; 713 } 715 } 716 uriCode = -1; 717 for (short j = 0; j < urisUsed; j++) { 718 if (uris[j].equals(uri)) { 719 uriCode = j; 720 break; 721 } 722 } 723 if (uriCode == -1) { 724 return -1; 725 } 726 } 727 728 int hash = (localName.hashCode() & 0x7fffffff) % 1023; 729 int depth = 1; 730 731 NameEntry entry; 732 733 if (hashslots[hash] == null) { 734 return -1; 735 } 736 737 entry = hashslots[hash]; 738 while (true) { 739 if (entry.uriCode == uriCode && entry.localName.equals(localName)) { 740 break; 741 } else { 742 NameEntry next = entry.nextEntry; 743 depth++; 744 if (next == null) { 745 return -1; 746 } else { 747 entry = next; 748 } 749 } 750 } 751 return (depth << 10) + hash; 752 } 753 754 757 758 public String getURIFromNamespaceCode(int code) { 759 return uris[code & 0xffff]; 760 } 761 762 765 766 public String getURIFromURICode(short code) { 767 return uris[code]; 768 } 769 770 773 774 public String getPrefixFromNamespaceCode(int code) { 775 return prefixes[code >> 16]; 777 } 778 779 789 790 public int allocateLexicalQName(CharSequence qname, boolean useDefault, NamespaceResolver resolver) 791 throws DynamicError { 792 try { 793 String [] parts = Name.getQNameParts(qname); 794 String uri = resolver.getURIForPrefix(parts[0], useDefault); 795 return allocate(parts[0], uri, parts[1]); 796 } catch (QNameException e) { 797 throw new DynamicError(e.getMessage()); 798 } 799 } 800 803 804 public int getFingerprintForExpandedName(String expandedName) { 805 806 String localName; 807 String namespace; 808 809 if (expandedName.charAt(0) == '{') { 810 int closeBrace = expandedName.indexOf('}'); 811 if (closeBrace < 0) { 812 throw new IllegalArgumentException ("No closing '}' in parameter name"); 813 } 814 namespace = expandedName.substring(1, closeBrace); 815 if (closeBrace == expandedName.length()) { 816 throw new IllegalArgumentException ("Missing local part in parameter name"); 817 } 818 localName = expandedName.substring(closeBrace + 1); 819 } else { 820 namespace = ""; 821 localName = expandedName; 822 } 823 824 return allocate("", namespace, localName); 825 } 826 827 830 831 public void setClientData(Class key, Object value) { 832 if (clientData == null) { 833 clientData = new HashMap (10); 834 } 835 clientData.put(key, value); 836 } 837 838 841 842 public Object getClientData(Class key) { 843 if (clientData == null) { 844 return null; 845 } 846 return clientData.get(key); 847 } 848 849 852 853 public synchronized void diagnosticDump() { 854 System.err.println("Contents of NamePool " + this); 855 for (int i = 0; i < 1024; i++) { 856 NameEntry entry = hashslots[i]; 857 int depth = 0; 858 while (entry != null) { 859 System.err.println("Fingerprint " + depth + '/' + i); 860 System.err.println(" local name = " + entry.localName + 861 " uri code = " + entry.uriCode); 862 entry = entry.nextEntry; 863 depth++; 864 } 865 } 866 867 for (int p = 0; p < prefixesUsed; p++) { 868 System.err.println("Prefix " + p + " = " + prefixes[p]); 869 } 870 for (int u = 0; u < urisUsed; u++) { 871 System.err.println("URI " + u + " = " + uris[u]); 872 System.err.println("Prefixes for URI " + u + " = " + prefixesForUri[u]); 873 } 874 } 875 876 880 881 public synchronized void statistics() { 882 int slots = 0; 883 int entries = 0; 884 for (int i = 0; i < 1024; i++) { 885 NameEntry entry = hashslots[i]; 886 if (entry != null) slots++; 887 while (entry != null) { 888 entry = entry.nextEntry; 889 entries++; 890 } 891 } 892 System.err.println("NamePool contents: " + entries + " entries in " + slots + " chains. " + 893 + prefixesUsed + " prefixes, " + urisUsed + " URIs"); 894 } 895 896 897 public static class NamePoolLimitException extends RuntimeException { 898 899 public NamePoolLimitException(String message) { 900 super(message); 901 } 902 } 903 904 } 905 906 | Popular Tags |