1 /* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.module; 27 28 import java.io.DataInput; 29 import java.io.DataInputStream; 30 import java.io.EOFException; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.UncheckedIOException; 34 import java.lang.module.ModuleDescriptor.Builder; 35 import java.lang.module.ModuleDescriptor.Requires; 36 import java.lang.module.ModuleDescriptor.Exports; 37 import java.lang.module.ModuleDescriptor.Opens; 38 import java.nio.ByteBuffer; 39 import java.nio.BufferUnderflowException; 40 import java.util.ArrayList; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.HashSet; 44 import java.util.List; 45 import java.util.Map; 46 import java.util.Set; 47 import java.util.function.Supplier; 48 49 import jdk.internal.module.ModuleHashes; 50 51 import static jdk.internal.module.ClassFileConstants.*; 52 53 54 /** 55 * Read module information from a {@code module-info} class file. 56 * 57 * @implNote The rationale for the hand-coded reader is startup performance 58 * and fine control over the throwing of InvalidModuleDescriptorException. 59 */ 60 61 final class ModuleInfo { 62 63 // supplies the set of packages when ModulePackages attribute not present 64 private final Supplier<Set<String>> packageFinder; 65 66 // indicates if the ModuleHashes attribute should be parsed 67 private final boolean parseHashes; 68 69 private ModuleInfo(Supplier<Set<String>> pf, boolean ph) { 70 packageFinder = pf; 71 parseHashes = ph; 72 } 73 74 private ModuleInfo(Supplier<Set<String>> pf) { 75 this(pf, true); 76 } 77 78 /** 79 * Reads a {@code module-info.class} from the given input stream. 80 * 81 * @throws InvalidModuleDescriptorException 82 * @throws IOException 83 */ 84 public static ModuleDescriptor read(InputStream in, 85 Supplier<Set<String>> pf) 86 throws IOException 87 { 88 try { 89 return new ModuleInfo(pf).doRead(new DataInputStream(in)); 90 } catch (IllegalArgumentException | IllegalStateException e) { 91 throw invalidModuleDescriptor(e.getMessage()); 92 } catch (EOFException x) { 93 throw truncatedModuleDescriptor(); 94 } 95 } 96 97 /** 98 * Reads a {@code module-info.class} from the given byte buffer. 99 * 100 * @throws InvalidModuleDescriptorException 101 * @throws UncheckedIOException 102 */ 103 public static ModuleDescriptor read(ByteBuffer bb, 104 Supplier<Set<String>> pf) 105 { 106 try { 107 return new ModuleInfo(pf).doRead(new DataInputWrapper(bb)); 108 } catch (IllegalArgumentException | IllegalStateException e) { 109 throw invalidModuleDescriptor(e.getMessage()); 110 } catch (EOFException x) { 111 throw truncatedModuleDescriptor(); 112 } catch (IOException ioe) { 113 throw new UncheckedIOException(ioe); 114 } 115 } 116 117 /** 118 * Reads a {@code module-info.class} from the given byte buffer 119 * but ignore the {@code ModuleHashes} attribute. 120 * 121 * @throws InvalidModuleDescriptorException 122 * @throws UncheckedIOException 123 */ 124 static ModuleDescriptor readIgnoringHashes(ByteBuffer bb, 125 Supplier<Set<String>> pf) 126 { 127 try { 128 return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb)); 129 } catch (IllegalArgumentException | IllegalStateException e) { 130 throw invalidModuleDescriptor(e.getMessage()); 131 } catch (EOFException x) { 132 throw truncatedModuleDescriptor(); 133 } catch (IOException ioe) { 134 throw new UncheckedIOException(ioe); 135 } 136 } 137 138 /** 139 * Reads the input as a module-info class file. 140 * 141 * @throws IOException 142 * @throws InvalidModuleDescriptorException 143 * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder 144 * because an identifier is not a legal Java identifier, duplicate 145 * exports, and many other reasons 146 */ 147 private ModuleDescriptor doRead(DataInput in) throws IOException { 148 149 int magic = in.readInt(); 150 if (magic != 0xCAFEBABE) 151 throw invalidModuleDescriptor("Bad magic number"); 152 153 int minor_version = in.readUnsignedShort(); 154 int major_version = in.readUnsignedShort(); 155 if (major_version < 53) { 156 throw invalidModuleDescriptor("Must be >= 53.0"); 157 } 158 159 ConstantPool cpool = new ConstantPool(in); 160 161 int access_flags = in.readUnsignedShort(); 162 if (access_flags != ACC_MODULE) 163 throw invalidModuleDescriptor("access_flags should be ACC_MODULE"); 164 165 int this_class = in.readUnsignedShort(); 166 if (this_class != 0) 167 throw invalidModuleDescriptor("this_class must be 0"); 168 169 int super_class = in.readUnsignedShort(); 170 if (super_class > 0) 171 throw invalidModuleDescriptor("bad #super_class"); 172 173 int interfaces_count = in.readUnsignedShort(); 174 if (interfaces_count > 0) 175 throw invalidModuleDescriptor("Bad #interfaces"); 176 177 int fields_count = in.readUnsignedShort(); 178 if (fields_count > 0) 179 throw invalidModuleDescriptor("Bad #fields"); 180 181 int methods_count = in.readUnsignedShort(); 182 if (methods_count > 0) 183 throw invalidModuleDescriptor("Bad #methods"); 184 185 int attributes_count = in.readUnsignedShort(); 186 187 // the names of the attributes found in the class file 188 Set<String> attributes = new HashSet<>(); 189 190 Builder builder = null; 191 Set<String> packages = null; 192 String version = null; 193 String mainClass = null; 194 String[] osValues = null; 195 ModuleHashes hashes = null; 196 197 for (int i = 0; i < attributes_count ; i++) { 198 int name_index = in.readUnsignedShort(); 199 String attribute_name = cpool.getUtf8(name_index); 200 int length = in.readInt(); 201 202 boolean added = attributes.add(attribute_name); 203 if (!added && isAttributeAtMostOnce(attribute_name)) { 204 throw invalidModuleDescriptor("More than one " 205 + attribute_name + " attribute"); 206 } 207 208 switch (attribute_name) { 209 210 case MODULE : 211 builder = readModuleAttribute(in, cpool); 212 break; 213 214 case MODULE_PACKAGES : 215 packages = readModulePackagesAttribute(in, cpool); 216 break; 217 218 case MODULE_VERSION : 219 version = readModuleVersionAttribute(in, cpool); 220 break; 221 222 case MODULE_MAIN_CLASS : 223 mainClass = readModuleMainClassAttribute(in, cpool); 224 break; 225 226 case MODULE_TARGET : 227 osValues = readModuleTargetAttribute(in, cpool); 228 break; 229 230 case MODULE_HASHES : 231 if (parseHashes) { 232 hashes = readModuleHashesAttribute(in, cpool); 233 } else { 234 in.skipBytes(length); 235 } 236 break; 237 238 default: 239 if (isAttributeDisallowed(attribute_name)) { 240 throw invalidModuleDescriptor(attribute_name 241 + " attribute not allowed"); 242 } else { 243 in.skipBytes(length); 244 } 245 246 } 247 } 248 249 // the Module attribute is required 250 if (builder == null) { 251 throw invalidModuleDescriptor(MODULE + " attribute not found"); 252 } 253 254 // If the ModulePackages attribute is not present then the packageFinder 255 // is used to find the set of packages 256 boolean usedPackageFinder = false; 257 if (packages == null && packageFinder != null) { 258 try { 259 packages = new HashSet<>(packageFinder.get()); 260 } catch (UncheckedIOException x) { 261 throw x.getCause(); 262 } 263 usedPackageFinder = true; 264 } 265 if (packages != null) { 266 for (String pn : builder.exportedAndOpenPackages()) { 267 if (!packages.contains(pn)) { 268 String tail; 269 if (usedPackageFinder) { 270 tail = " not found by package finder"; 271 } else { 272 tail = " missing from ModulePackages attribute"; 273 } 274 throw invalidModuleDescriptor("Package " + pn + tail); 275 } 276 packages.remove(pn); 277 } 278 builder.contains(packages); 279 } 280 281 if (version != null) 282 builder.version(version); 283 if (mainClass != null) 284 builder.mainClass(mainClass); 285 if (osValues != null) { 286 if (osValues[0] != null) builder.osName(osValues[0]); 287 if (osValues[1] != null) builder.osArch(osValues[1]); 288 if (osValues[2] != null) builder.osVersion(osValues[2]); 289 } 290 if (hashes != null) 291 builder.hashes(hashes); 292 293 return builder.build(); 294 } 295 296 /** 297 * Reads the Module attribute, returning the ModuleDescriptor.Builder to 298 * build the corresponding ModuleDescriptor. 299 */ 300 private Builder readModuleAttribute(DataInput in, ConstantPool cpool) 301 throws IOException 302 { 303 // module_name 304 int module_name_index = in.readUnsignedShort(); 305 String mn = cpool.getUtf8AsBinaryName(module_name_index); 306 307 Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false); 308 309 int module_flags = in.readUnsignedShort(); 310 boolean open = ((module_flags & ACC_OPEN) != 0); 311 if (open) 312 builder.open(true); 313 if ((module_flags & ACC_SYNTHETIC) != 0) 314 builder.synthetic(true); 315 316 int requires_count = in.readUnsignedShort(); 317 boolean requiresJavaBase = false; 318 for (int i=0; i<requires_count; i++) { 319 int index = in.readUnsignedShort(); 320 int flags = in.readUnsignedShort(); 321 String dn = cpool.getUtf8AsBinaryName(index); 322 Set<Requires.Modifier> mods; 323 if (flags == 0) { 324 mods = Collections.emptySet(); 325 } else { 326 mods = new HashSet<>(); 327 if ((flags & ACC_TRANSITIVE) != 0) 328 mods.add(Requires.Modifier.TRANSITIVE); 329 if ((flags & ACC_STATIC_PHASE) != 0) 330 mods.add(Requires.Modifier.STATIC); 331 if ((flags & ACC_SYNTHETIC) != 0) 332 mods.add(Requires.Modifier.SYNTHETIC); 333 if ((flags & ACC_MANDATED) != 0) 334 mods.add(Requires.Modifier.MANDATED); 335 } 336 builder.requires(mods, dn); 337 if (dn.equals("java.base")) 338 requiresJavaBase = true; 339 } 340 if (mn.equals("java.base")) { 341 if (requires_count > 0) { 342 throw invalidModuleDescriptor("The requires table for java.base" 343 + " must be 0 length"); 344 } 345 } else if (!requiresJavaBase) { 346 throw invalidModuleDescriptor("The requires table must have" 347 + " an entry for java.base"); 348 } 349 350 int exports_count = in.readUnsignedShort(); 351 if (exports_count > 0) { 352 for (int i=0; i<exports_count; i++) { 353 int index = in.readUnsignedShort(); 354 String pkg = cpool.getUtf8AsBinaryName(index); 355 356 Set<Exports.Modifier> mods; 357 int flags = in.readUnsignedShort(); 358 if (flags == 0) { 359 mods = Collections.emptySet(); 360 } else { 361 mods = new HashSet<>(); 362 if ((flags & ACC_SYNTHETIC) != 0) 363 mods.add(Exports.Modifier.SYNTHETIC); 364 if ((flags & ACC_MANDATED) != 0) 365 mods.add(Exports.Modifier.MANDATED); 366 } 367 368 int exports_to_count = in.readUnsignedShort(); 369 if (exports_to_count > 0) { 370 Set<String> targets = new HashSet<>(exports_to_count); 371 for (int j=0; j<exports_to_count; j++) { 372 int exports_to_index = in.readUnsignedShort(); 373 targets.add(cpool.getUtf8AsBinaryName(exports_to_index)); 374 } 375 builder.exports(mods, pkg, targets); 376 } else { 377 builder.exports(mods, pkg); 378 } 379 } 380 } 381 382 int opens_count = in.readUnsignedShort(); 383 if (opens_count > 0) { 384 if (open) { 385 throw invalidModuleDescriptor("The opens table for an open" 386 + " module must be 0 length"); 387 } 388 for (int i=0; i<opens_count; i++) { 389 int index = in.readUnsignedShort(); 390 String pkg = cpool.getUtf8AsBinaryName(index); 391 392 Set<Opens.Modifier> mods; 393 int flags = in.readUnsignedShort(); 394 if (flags == 0) { 395 mods = Collections.emptySet(); 396 } else { 397 mods = new HashSet<>(); 398 if ((flags & ACC_SYNTHETIC) != 0) 399 mods.add(Opens.Modifier.SYNTHETIC); 400 if ((flags & ACC_MANDATED) != 0) 401 mods.add(Opens.Modifier.MANDATED); 402 } 403 404 int open_to_count = in.readUnsignedShort(); 405 if (open_to_count > 0) { 406 Set<String> targets = new HashSet<>(open_to_count); 407 for (int j=0; j<open_to_count; j++) { 408 int opens_to_index = in.readUnsignedShort(); 409 targets.add(cpool.getUtf8AsBinaryName(opens_to_index)); 410 } 411 builder.opens(mods, pkg, targets); 412 } else { 413 builder.opens(mods, pkg); 414 } 415 } 416 } 417 418 int uses_count = in.readUnsignedShort(); 419 if (uses_count > 0) { 420 for (int i=0; i<uses_count; i++) { 421 int index = in.readUnsignedShort(); 422 String sn = cpool.getClassNameAsBinaryName(index); 423 builder.uses(sn); 424 } 425 } 426 427 int provides_count = in.readUnsignedShort(); 428 if (provides_count > 0) { 429 for (int i=0; i<provides_count; i++) { 430 int index = in.readUnsignedShort(); 431 String sn = cpool.getClassNameAsBinaryName(index); 432 int with_count = in.readUnsignedShort(); 433 List<String> providers = new ArrayList<>(with_count); 434 for (int j=0; j<with_count; j++) { 435 index = in.readUnsignedShort(); 436 String pn = cpool.getClassNameAsBinaryName(index); 437 providers.add(pn); 438 } 439 builder.provides(sn, providers); 440 } 441 } 442 443 return builder; 444 } 445 446 /** 447 * Reads the ModulePackages attribute 448 */ 449 private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool) 450 throws IOException 451 { 452 int package_count = in.readUnsignedShort(); 453 Set<String> packages = new HashSet<>(package_count); 454 for (int i=0; i<package_count; i++) { 455 int index = in.readUnsignedShort(); 456 String pn = cpool.getUtf8AsBinaryName(index); 457 packages.add(pn); 458 } 459 return packages; 460 } 461 462 /** 463 * Reads the ModuleVersion attribute 464 */ 465 private String readModuleVersionAttribute(DataInput in, ConstantPool cpool) 466 throws IOException 467 { 468 int index = in.readUnsignedShort(); 469 return cpool.getUtf8(index); 470 } 471 472 /** 473 * Reads the ModuleMainClass attribute 474 */ 475 private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool) 476 throws IOException 477 { 478 int index = in.readUnsignedShort(); 479 return cpool.getClassNameAsBinaryName(index); 480 } 481 482 /** 483 * Reads the ModuleTarget attribute 484 */ 485 private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool) 486 throws IOException 487 { 488 String[] values = new String[3]; 489 490 int name_index = in.readUnsignedShort(); 491 if (name_index != 0) 492 values[0] = cpool.getUtf8(name_index); 493 494 int arch_index = in.readUnsignedShort(); 495 if (arch_index != 0) 496 values[1] = cpool.getUtf8(arch_index); 497 498 int version_index = in.readUnsignedShort(); 499 if (version_index != 0) 500 values[2] = cpool.getUtf8(version_index); 501 502 return values; 503 } 504 505 506 /** 507 * Reads the ModuleHashes attribute 508 */ 509 private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool) 510 throws IOException 511 { 512 int algorithm_index = in.readUnsignedShort(); 513 String algorithm = cpool.getUtf8(algorithm_index); 514 515 int hash_count = in.readUnsignedShort(); 516 Map<String, byte[]> map = new HashMap<>(hash_count); 517 for (int i=0; i<hash_count; i++) { 518 int module_name_index = in.readUnsignedShort(); 519 String mn = cpool.getUtf8AsBinaryName(module_name_index); 520 int hash_length = in.readUnsignedShort(); 521 if (hash_length == 0) { 522 throw invalidModuleDescriptor("hash_length == 0"); 523 } 524 byte[] hash = new byte[hash_length]; 525 in.readFully(hash); 526 map.put(mn, hash); 527 } 528 529 return new ModuleHashes(algorithm, map); 530 } 531 532 533 /** 534 * Returns true if the given attribute can be present at most once 535 * in the class file. Returns false otherwise. 536 */ 537 private static boolean isAttributeAtMostOnce(String name) { 538 539 if (name.equals(MODULE) || 540 name.equals(SOURCE_FILE) || 541 name.equals(SDE) || 542 name.equals(MODULE_PACKAGES) || 543 name.equals(MODULE_VERSION) || 544 name.equals(MODULE_MAIN_CLASS) || 545 name.equals(MODULE_TARGET) || 546 name.equals(MODULE_HASHES)) 547 return true; 548 549 return false; 550 } 551 552 /** 553 * Return true if the given attribute name is the name of a pre-defined 554 * attribute that is not allowed in the class file. 555 * 556 * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and 557 * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear. 558 */ 559 private static boolean isAttributeDisallowed(String name) { 560 Set<String> notAllowed = predefinedNotAllowed; 561 if (notAllowed == null) { 562 notAllowed = Set.of( 563 "ConstantValue", 564 "Code", 565 "StackMapTable", 566 "Exceptions", 567 "EnclosingMethod", 568 "Signature", 569 "LineNumberTable", 570 "LocalVariableTable", 571 "LocalVariableTypeTable", 572 "RuntimeVisibleParameterAnnotations", 573 "RuntimeInvisibleParameterAnnotations", 574 "RuntimeVisibleTypeAnnotations", 575 "RuntimeInvisibleTypeAnnotations", 576 "Synthetic", 577 "AnnotationDefault", 578 "BootstrapMethods", 579 "MethodParameters"); 580 predefinedNotAllowed = notAllowed; 581 } 582 return notAllowed.contains(name); 583 } 584 585 // lazily created set the pre-defined attributes that are not allowed 586 private static volatile Set<String> predefinedNotAllowed; 587 588 589 /** 590 * The constant pool in a class file. 591 */ 592 private static class ConstantPool { 593 static final int CONSTANT_Utf8 = 1; 594 static final int CONSTANT_Integer = 3; 595 static final int CONSTANT_Float = 4; 596 static final int CONSTANT_Long = 5; 597 static final int CONSTANT_Double = 6; 598 static final int CONSTANT_Class = 7; 599 static final int CONSTANT_String = 8; 600 static final int CONSTANT_Fieldref = 9; 601 static final int CONSTANT_Methodref = 10; 602 static final int CONSTANT_InterfaceMethodref = 11; 603 static final int CONSTANT_NameAndType = 12; 604 static final int CONSTANT_MethodHandle = 15; 605 static final int CONSTANT_MethodType = 16; 606 static final int CONSTANT_InvokeDynamic = 18; 607 608 private static class Entry { 609 protected Entry(int tag) { 610 this.tag = tag; 611 } 612 final int tag; 613 } 614 615 private static class IndexEntry extends Entry { 616 IndexEntry(int tag, int index) { 617 super(tag); 618 this.index = index; 619 } 620 final int index; 621 } 622 623 private static class Index2Entry extends Entry { 624 Index2Entry(int tag, int index1, int index2) { 625 super(tag); 626 this.index1 = index1; 627 this.index2 = index2; 628 } 629 final int index1, index2; 630 } 631 632 private static class ValueEntry extends Entry { 633 ValueEntry(int tag, Object value) { 634 super(tag); 635 this.value = value; 636 } 637 final Object value; 638 } 639 640 final Entry[] pool; 641 642 ConstantPool(DataInput in) throws IOException { 643 int count = in.readUnsignedShort(); 644 pool = new Entry[count]; 645 646 for (int i = 1; i < count; i++) { 647 int tag = in.readUnsignedByte(); 648 switch (tag) { 649 650 case CONSTANT_Utf8: 651 String svalue = in.readUTF(); 652 pool[i] = new ValueEntry(tag, svalue); 653 break; 654 655 case CONSTANT_Class: 656 case CONSTANT_String: 657 int index = in.readUnsignedShort(); 658 pool[i] = new IndexEntry(tag, index); 659 break; 660 661 case CONSTANT_Double: 662 double dvalue = in.readDouble(); 663 pool[i] = new ValueEntry(tag, dvalue); 664 i++; 665 break; 666 667 case CONSTANT_Fieldref: 668 case CONSTANT_InterfaceMethodref: 669 case CONSTANT_Methodref: 670 case CONSTANT_InvokeDynamic: 671 case CONSTANT_NameAndType: 672 int index1 = in.readUnsignedShort(); 673 int index2 = in.readUnsignedShort(); 674 pool[i] = new Index2Entry(tag, index1, index2); 675 break; 676 677 case CONSTANT_MethodHandle: 678 int refKind = in.readUnsignedByte(); 679 index = in.readUnsignedShort(); 680 pool[i] = new Index2Entry(tag, refKind, index); 681 break; 682 683 case CONSTANT_MethodType: 684 index = in.readUnsignedShort(); 685 pool[i] = new IndexEntry(tag, index); 686 break; 687 688 case CONSTANT_Float: 689 float fvalue = in.readFloat(); 690 pool[i] = new ValueEntry(tag, fvalue); 691 break; 692 693 case CONSTANT_Integer: 694 int ivalue = in.readInt(); 695 pool[i] = new ValueEntry(tag, ivalue); 696 break; 697 698 case CONSTANT_Long: 699 long lvalue = in.readLong(); 700 pool[i] = new ValueEntry(tag, lvalue); 701 i++; 702 break; 703 704 default: 705 throw invalidModuleDescriptor("Bad constant pool entry: " 706 + i); 707 } 708 } 709 } 710 711 String getClassName(int index) { 712 checkIndex(index); 713 Entry e = pool[index]; 714 if (e.tag != CONSTANT_Class) { 715 throw invalidModuleDescriptor("CONSTANT_Class expected at entry: " 716 + index); 717 } 718 return getUtf8(((IndexEntry) e).index); 719 } 720 721 String getClassNameAsBinaryName(int index) { 722 String value = getClassName(index); 723 return value.replace('/', '.'); // internal form -> binary name 724 } 725 726 String getUtf8(int index) { 727 checkIndex(index); 728 Entry e = pool[index]; 729 if (e.tag != CONSTANT_Utf8) { 730 throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: " 731 + index); 732 } 733 return (String) (((ValueEntry) e).value); 734 } 735 736 String getUtf8AsBinaryName(int index) { 737 String value = getUtf8(index); 738 return value.replace('/', '.'); // internal -> binary name 739 } 740 741 void checkIndex(int index) { 742 if (index < 1 || index >= pool.length) 743 throw invalidModuleDescriptor("Index into constant pool out of range"); 744 } 745 } 746 747 /** 748 * A DataInput implementation that reads from a ByteBuffer. 749 */ 750 private static class DataInputWrapper implements DataInput { 751 private final ByteBuffer bb; 752 753 DataInputWrapper(ByteBuffer bb) { 754 this.bb = bb; 755 } 756 757 @Override 758 public void readFully(byte b[]) throws IOException { 759 readFully(b, 0, b.length); 760 } 761 762 @Override 763 public void readFully(byte b[], int off, int len) throws IOException { 764 try { 765 bb.get(b, off, len); 766 } catch (BufferUnderflowException e) { 767 throw new EOFException(e.getMessage()); 768 } 769 } 770 771 @Override 772 public int skipBytes(int n) { 773 int skip = Math.min(n, bb.remaining()); 774 bb.position(bb.position() + skip); 775 return skip; 776 } 777 778 @Override 779 public boolean readBoolean() throws IOException { 780 try { 781 int ch = bb.get(); 782 return (ch != 0); 783 } catch (BufferUnderflowException e) { 784 throw new EOFException(e.getMessage()); 785 } 786 } 787 788 @Override 789 public byte readByte() throws IOException { 790 try { 791 return bb.get(); 792 } catch (BufferUnderflowException e) { 793 throw new EOFException(e.getMessage()); 794 } 795 } 796 797 @Override 798 public int readUnsignedByte() throws IOException { 799 try { 800 return ((int) bb.get()) & 0xff; 801 } catch (BufferUnderflowException e) { 802 throw new EOFException(e.getMessage()); 803 } 804 } 805 806 @Override 807 public short readShort() throws IOException { 808 try { 809 return bb.getShort(); 810 } catch (BufferUnderflowException e) { 811 throw new EOFException(e.getMessage()); 812 } 813 } 814 815 @Override 816 public int readUnsignedShort() throws IOException { 817 try { 818 return ((int) bb.getShort()) & 0xffff; 819 } catch (BufferUnderflowException e) { 820 throw new EOFException(e.getMessage()); 821 } 822 } 823 824 @Override 825 public char readChar() throws IOException { 826 try { 827 return bb.getChar(); 828 } catch (BufferUnderflowException e) { 829 throw new EOFException(e.getMessage()); 830 } 831 } 832 833 @Override 834 public int readInt() throws IOException { 835 try { 836 return bb.getInt(); 837 } catch (BufferUnderflowException e) { 838 throw new EOFException(e.getMessage()); 839 } 840 } 841 842 @Override 843 public long readLong() throws IOException { 844 try { 845 return bb.getLong(); 846 } catch (BufferUnderflowException e) { 847 throw new EOFException(e.getMessage()); 848 } 849 } 850 851 @Override 852 public float readFloat() throws IOException { 853 try { 854 return bb.getFloat(); 855 } catch (BufferUnderflowException e) { 856 throw new EOFException(e.getMessage()); 857 } 858 } 859 860 @Override 861 public double readDouble() throws IOException { 862 try { 863 return bb.getDouble(); 864 } catch (BufferUnderflowException e) { 865 throw new EOFException(e.getMessage()); 866 } 867 } 868 869 @Override 870 public String readLine() { 871 throw new RuntimeException("not implemented"); 872 } 873 874 @Override 875 public String readUTF() throws IOException { 876 // ### Need to measure the performance and feasibility of using 877 // the UTF-8 decoder instead. 878 return DataInputStream.readUTF(this); 879 } 880 } 881 882 /** 883 * Returns an InvalidModuleDescriptorException with the given detail 884 * message 885 */ 886 private static InvalidModuleDescriptorException 887 invalidModuleDescriptor(String msg) { 888 return new InvalidModuleDescriptorException(msg); 889 } 890 891 /** 892 * Returns an InvalidModuleDescriptorException with a detail message to 893 * indicate that the class file is truncated. 894 */ 895 private static InvalidModuleDescriptorException truncatedModuleDescriptor() { 896 return invalidModuleDescriptor("Truncated module-info.class"); 897 } 898 899 }