72 // indicates if the ModuleHashes attribute should be parsed 73 private final boolean parseHashes; 74 75 private ModuleInfo(Supplier<Set<String>> pf, boolean ph) { 76 packageFinder = pf; 77 parseHashes = ph; 78 } 79 80 private ModuleInfo(Supplier<Set<String>> pf) { 81 this(pf, true); 82 } 83 84 /** 85 * A holder class for the ModuleDescriptor that is created by reading the 86 * Module and other standard class file attributes. It also holds the objects 87 * that represent the non-standard class file attributes that are read from 88 * the class file. 89 */ 90 public static final class Attributes { 91 private final ModuleDescriptor descriptor; 92 private final ModuleHashes recordedHashes; 93 private final ModuleResolution moduleResolution; 94 Attributes(ModuleDescriptor descriptor, 95 ModuleHashes recordedHashes, 96 ModuleResolution moduleResolution) { 97 this.descriptor = descriptor; 98 this.recordedHashes = recordedHashes; 99 this.moduleResolution = moduleResolution; 100 } 101 public ModuleDescriptor descriptor() { 102 return descriptor; 103 } 104 public ModuleHashes recordedHashes() { 105 return recordedHashes; 106 } 107 public ModuleResolution moduleResolution() { 108 return moduleResolution; 109 } 110 } 111 112 113 /** 114 * Reads a {@code module-info.class} from the given input stream. 115 * 116 * @throws InvalidModuleDescriptorException 117 * @throws IOException 118 */ 119 public static Attributes read(InputStream in, Supplier<Set<String>> pf) 120 throws IOException 121 { 122 try { 123 return new ModuleInfo(pf).doRead(new DataInputStream(in)); 204 int interfaces_count = in.readUnsignedShort(); 205 if (interfaces_count > 0) 206 throw invalidModuleDescriptor("Bad #interfaces"); 207 208 int fields_count = in.readUnsignedShort(); 209 if (fields_count > 0) 210 throw invalidModuleDescriptor("Bad #fields"); 211 212 int methods_count = in.readUnsignedShort(); 213 if (methods_count > 0) 214 throw invalidModuleDescriptor("Bad #methods"); 215 216 int attributes_count = in.readUnsignedShort(); 217 218 // the names of the attributes found in the class file 219 Set<String> attributes = new HashSet<>(); 220 221 Builder builder = null; 222 Set<String> allPackages = null; 223 String mainClass = null; 224 String[] osValues = null; 225 ModuleHashes hashes = null; 226 ModuleResolution moduleResolution = null; 227 228 for (int i = 0; i < attributes_count ; i++) { 229 int name_index = in.readUnsignedShort(); 230 String attribute_name = cpool.getUtf8(name_index); 231 int length = in.readInt(); 232 233 boolean added = attributes.add(attribute_name); 234 if (!added && isAttributeAtMostOnce(attribute_name)) { 235 throw invalidModuleDescriptor("More than one " 236 + attribute_name + " attribute"); 237 } 238 239 switch (attribute_name) { 240 241 case MODULE : 242 builder = readModuleAttribute(in, cpool); 243 break; 244 245 case MODULE_PACKAGES : 246 allPackages = readModulePackagesAttribute(in, cpool); 247 break; 248 249 case MODULE_MAIN_CLASS : 250 mainClass = readModuleMainClassAttribute(in, cpool); 251 break; 252 253 case MODULE_TARGET : 254 osValues = readModuleTargetAttribute(in, cpool); 255 break; 256 257 case MODULE_HASHES : 258 if (parseHashes) { 259 hashes = readModuleHashesAttribute(in, cpool); 260 } else { 261 in.skipBytes(length); 262 } 263 break; 264 265 case MODULE_RESOLUTION : 266 moduleResolution = readModuleResolution(in, cpool); 267 break; 268 269 default: 270 if (isAttributeDisallowed(attribute_name)) { 271 throw invalidModuleDescriptor(attribute_name 272 + " attribute not allowed"); 273 } else { 274 in.skipBytes(length); 275 } 276 277 } 278 } 279 280 // the Module attribute is required 281 if (builder == null) { 282 throw invalidModuleDescriptor(MODULE + " attribute not found"); 283 } 284 285 // ModuleMainClass and ModuleTarget attributes 286 if (mainClass != null) { 287 builder.mainClass(mainClass); 288 } 289 if (osValues != null) { 290 if (osValues[0] != null) builder.osName(osValues[0]); 291 if (osValues[1] != null) builder.osArch(osValues[1]); 292 if (osValues[2] != null) builder.osVersion(osValues[2]); 293 } 294 295 // If the ModulePackages attribute is not present then the packageFinder 296 // is used to find the set of packages 297 boolean usedPackageFinder = false; 298 if (allPackages == null && packageFinder != null) { 299 try { 300 allPackages = packageFinder.get(); 301 } catch (UncheckedIOException x) { 302 throw x.getCause(); 303 } 304 usedPackageFinder = true; 305 } 306 if (allPackages != null) { 307 Set<String> knownPackages = JLMA.packages(builder); 308 if (!allPackages.containsAll(knownPackages)) { 309 Set<String> missingPackages = new HashSet<>(knownPackages); 310 missingPackages.removeAll(allPackages); 311 assert !missingPackages.isEmpty(); 312 String missingPackage = missingPackages.iterator().next(); 313 String tail; 314 if (usedPackageFinder) { 315 tail = " not found in module"; 316 } else { 317 tail = " missing from ModulePackages class file attribute"; 318 } 319 throw invalidModuleDescriptor("Package " + missingPackage + tail); 320 321 } 322 builder.packages(allPackages); 323 } 324 325 ModuleDescriptor descriptor = builder.build(); 326 return new Attributes(descriptor, hashes, moduleResolution); 327 } 328 329 /** 330 * Reads the Module attribute, returning the ModuleDescriptor.Builder to 331 * build the corresponding ModuleDescriptor. 332 */ 333 private Builder readModuleAttribute(DataInput in, ConstantPool cpool) 334 throws IOException 335 { 336 // module_name 337 int module_name_index = in.readUnsignedShort(); 338 String mn = cpool.getModuleName(module_name_index); 339 340 int module_flags = in.readUnsignedShort(); 341 342 Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>(); 343 boolean open = ((module_flags & ACC_OPEN) != 0); 344 if (open) 345 modifiers.add(ModuleDescriptor.Modifier.OPEN); 346 if ((module_flags & ACC_SYNTHETIC) != 0) 405 int exports_index = in.readUnsignedShort(); 406 String pkg = cpool.getPackageName(exports_index); 407 408 Set<Exports.Modifier> mods; 409 int exports_flags = in.readUnsignedShort(); 410 if (exports_flags == 0) { 411 mods = Collections.emptySet(); 412 } else { 413 mods = new HashSet<>(); 414 if ((exports_flags & ACC_SYNTHETIC) != 0) 415 mods.add(Exports.Modifier.SYNTHETIC); 416 if ((exports_flags & ACC_MANDATED) != 0) 417 mods.add(Exports.Modifier.MANDATED); 418 } 419 420 int exports_to_count = in.readUnsignedShort(); 421 if (exports_to_count > 0) { 422 Set<String> targets = new HashSet<>(exports_to_count); 423 for (int j=0; j<exports_to_count; j++) { 424 int exports_to_index = in.readUnsignedShort(); 425 targets.add(cpool.getModuleName(exports_to_index)); 426 } 427 builder.exports(mods, pkg, targets); 428 } else { 429 builder.exports(mods, pkg); 430 } 431 } 432 } 433 434 int opens_count = in.readUnsignedShort(); 435 if (opens_count > 0) { 436 if (open) { 437 throw invalidModuleDescriptor("The opens table for an open" 438 + " module must be 0 length"); 439 } 440 for (int i=0; i<opens_count; i++) { 441 int opens_index = in.readUnsignedShort(); 442 String pkg = cpool.getPackageName(opens_index); 443 444 Set<Opens.Modifier> mods; 445 int opens_flags = in.readUnsignedShort(); 446 if (opens_flags == 0) { 447 mods = Collections.emptySet(); 448 } else { 449 mods = new HashSet<>(); 450 if ((opens_flags & ACC_SYNTHETIC) != 0) 451 mods.add(Opens.Modifier.SYNTHETIC); 452 if ((opens_flags & ACC_MANDATED) != 0) 453 mods.add(Opens.Modifier.MANDATED); 454 } 455 456 int open_to_count = in.readUnsignedShort(); 457 if (open_to_count > 0) { 458 Set<String> targets = new HashSet<>(open_to_count); 459 for (int j=0; j<open_to_count; j++) { 460 int opens_to_index = in.readUnsignedShort(); 461 targets.add(cpool.getModuleName(opens_to_index)); 462 } 463 builder.opens(mods, pkg, targets); 464 } else { 465 builder.opens(mods, pkg); 466 } 467 } 468 } 469 470 int uses_count = in.readUnsignedShort(); 471 if (uses_count > 0) { 472 for (int i=0; i<uses_count; i++) { 473 int index = in.readUnsignedShort(); 474 String sn = cpool.getClassName(index); 475 builder.uses(sn); 476 } 477 } 478 479 int provides_count = in.readUnsignedShort(); 480 if (provides_count > 0) { 481 for (int i=0; i<provides_count; i++) { 482 int index = in.readUnsignedShort(); 483 String sn = cpool.getClassName(index); 484 int with_count = in.readUnsignedShort(); 485 List<String> providers = new ArrayList<>(with_count); 486 for (int j=0; j<with_count; j++) { 487 index = in.readUnsignedShort(); 488 String pn = cpool.getClassName(index); 489 providers.add(pn); 490 } 491 builder.provides(sn, providers); 492 } 493 } 494 495 return builder; 496 } 497 498 /** 499 * Reads the ModulePackages attribute 500 */ 501 private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool) 502 throws IOException 503 { 504 int package_count = in.readUnsignedShort(); 505 Set<String> packages = new HashSet<>(package_count); 506 for (int i=0; i<package_count; i++) { 507 int index = in.readUnsignedShort(); 508 String pn = cpool.getPackageName(index); 509 boolean added = packages.add(pn); 511 throw invalidModuleDescriptor("Package " + pn + " in ModulePackages" 512 + "attribute more than once"); 513 } 514 } 515 return packages; 516 } 517 518 /** 519 * Reads the ModuleMainClass attribute 520 */ 521 private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool) 522 throws IOException 523 { 524 int index = in.readUnsignedShort(); 525 return cpool.getClassName(index); 526 } 527 528 /** 529 * Reads the ModuleTarget attribute 530 */ 531 private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool) 532 throws IOException 533 { 534 String[] values = new String[3]; 535 536 int name_index = in.readUnsignedShort(); 537 if (name_index != 0) 538 values[0] = cpool.getUtf8(name_index); 539 540 int arch_index = in.readUnsignedShort(); 541 if (arch_index != 0) 542 values[1] = cpool.getUtf8(arch_index); 543 544 int version_index = in.readUnsignedShort(); 545 if (version_index != 0) 546 values[2] = cpool.getUtf8(version_index); 547 548 return values; 549 } 550 551 552 /** 553 * Reads the ModuleHashes attribute 554 */ 555 private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool) 556 throws IOException 557 { 558 int algorithm_index = in.readUnsignedShort(); 559 String algorithm = cpool.getUtf8(algorithm_index); 560 561 int hash_count = in.readUnsignedShort(); 562 Map<String, byte[]> map = new HashMap<>(hash_count); 563 for (int i=0; i<hash_count; i++) { 564 int module_name_index = in.readUnsignedShort(); 565 String mn = cpool.getModuleName(module_name_index); 566 int hash_length = in.readUnsignedShort(); 567 if (hash_length == 0) { 568 throw invalidModuleDescriptor("hash_length == 0"); | 72 // indicates if the ModuleHashes attribute should be parsed 73 private final boolean parseHashes; 74 75 private ModuleInfo(Supplier<Set<String>> pf, boolean ph) { 76 packageFinder = pf; 77 parseHashes = ph; 78 } 79 80 private ModuleInfo(Supplier<Set<String>> pf) { 81 this(pf, true); 82 } 83 84 /** 85 * A holder class for the ModuleDescriptor that is created by reading the 86 * Module and other standard class file attributes. It also holds the objects 87 * that represent the non-standard class file attributes that are read from 88 * the class file. 89 */ 90 public static final class Attributes { 91 private final ModuleDescriptor descriptor; 92 private final ModuleTarget target; 93 private final ModuleHashes recordedHashes; 94 private final ModuleResolution moduleResolution; 95 Attributes(ModuleDescriptor descriptor, 96 ModuleTarget target, 97 ModuleHashes recordedHashes, 98 ModuleResolution moduleResolution) { 99 this.descriptor = descriptor; 100 this.target = target; 101 this.recordedHashes = recordedHashes; 102 this.moduleResolution = moduleResolution; 103 } 104 public ModuleDescriptor descriptor() { 105 return descriptor; 106 } 107 public ModuleTarget target() { 108 return target; 109 } 110 public ModuleHashes recordedHashes() { 111 return recordedHashes; 112 } 113 public ModuleResolution moduleResolution() { 114 return moduleResolution; 115 } 116 } 117 118 119 /** 120 * Reads a {@code module-info.class} from the given input stream. 121 * 122 * @throws InvalidModuleDescriptorException 123 * @throws IOException 124 */ 125 public static Attributes read(InputStream in, Supplier<Set<String>> pf) 126 throws IOException 127 { 128 try { 129 return new ModuleInfo(pf).doRead(new DataInputStream(in)); 210 int interfaces_count = in.readUnsignedShort(); 211 if (interfaces_count > 0) 212 throw invalidModuleDescriptor("Bad #interfaces"); 213 214 int fields_count = in.readUnsignedShort(); 215 if (fields_count > 0) 216 throw invalidModuleDescriptor("Bad #fields"); 217 218 int methods_count = in.readUnsignedShort(); 219 if (methods_count > 0) 220 throw invalidModuleDescriptor("Bad #methods"); 221 222 int attributes_count = in.readUnsignedShort(); 223 224 // the names of the attributes found in the class file 225 Set<String> attributes = new HashSet<>(); 226 227 Builder builder = null; 228 Set<String> allPackages = null; 229 String mainClass = null; 230 ModuleTarget moduleTarget = null; 231 ModuleHashes moduelHashes = null; 232 ModuleResolution moduleResolution = null; 233 234 for (int i = 0; i < attributes_count ; i++) { 235 int name_index = in.readUnsignedShort(); 236 String attribute_name = cpool.getUtf8(name_index); 237 int length = in.readInt(); 238 239 boolean added = attributes.add(attribute_name); 240 if (!added && isAttributeAtMostOnce(attribute_name)) { 241 throw invalidModuleDescriptor("More than one " 242 + attribute_name + " attribute"); 243 } 244 245 switch (attribute_name) { 246 247 case MODULE : 248 builder = readModuleAttribute(in, cpool); 249 break; 250 251 case MODULE_PACKAGES : 252 allPackages = readModulePackagesAttribute(in, cpool); 253 break; 254 255 case MODULE_MAIN_CLASS : 256 mainClass = readModuleMainClassAttribute(in, cpool); 257 break; 258 259 case MODULE_TARGET : 260 moduleTarget = readModuleTargetAttribute(in, cpool); 261 break; 262 263 case MODULE_HASHES : 264 if (parseHashes) { 265 moduelHashes = readModuleHashesAttribute(in, cpool); 266 } else { 267 in.skipBytes(length); 268 } 269 break; 270 271 case MODULE_RESOLUTION : 272 moduleResolution = readModuleResolution(in, cpool); 273 break; 274 275 default: 276 if (isAttributeDisallowed(attribute_name)) { 277 throw invalidModuleDescriptor(attribute_name 278 + " attribute not allowed"); 279 } else { 280 in.skipBytes(length); 281 } 282 283 } 284 } 285 286 // the Module attribute is required 287 if (builder == null) { 288 throw invalidModuleDescriptor(MODULE + " attribute not found"); 289 } 290 291 // ModuleMainClass attribute 292 if (mainClass != null) { 293 builder.mainClass(mainClass); 294 } 295 296 // If the ModulePackages attribute is not present then the packageFinder 297 // is used to find the set of packages 298 boolean usedPackageFinder = false; 299 if (allPackages == null && packageFinder != null) { 300 try { 301 allPackages = packageFinder.get(); 302 } catch (UncheckedIOException x) { 303 throw x.getCause(); 304 } 305 usedPackageFinder = true; 306 } 307 if (allPackages != null) { 308 Set<String> knownPackages = JLMA.packages(builder); 309 if (!allPackages.containsAll(knownPackages)) { 310 Set<String> missingPackages = new HashSet<>(knownPackages); 311 missingPackages.removeAll(allPackages); 312 assert !missingPackages.isEmpty(); 313 String missingPackage = missingPackages.iterator().next(); 314 String tail; 315 if (usedPackageFinder) { 316 tail = " not found in module"; 317 } else { 318 tail = " missing from ModulePackages class file attribute"; 319 } 320 throw invalidModuleDescriptor("Package " + missingPackage + tail); 321 322 } 323 builder.packages(allPackages); 324 } 325 326 ModuleDescriptor descriptor = builder.build(); 327 return new Attributes(descriptor, 328 moduleTarget, 329 moduelHashes, 330 moduleResolution); 331 } 332 333 /** 334 * Reads the Module attribute, returning the ModuleDescriptor.Builder to 335 * build the corresponding ModuleDescriptor. 336 */ 337 private Builder readModuleAttribute(DataInput in, ConstantPool cpool) 338 throws IOException 339 { 340 // module_name 341 int module_name_index = in.readUnsignedShort(); 342 String mn = cpool.getModuleName(module_name_index); 343 344 int module_flags = in.readUnsignedShort(); 345 346 Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>(); 347 boolean open = ((module_flags & ACC_OPEN) != 0); 348 if (open) 349 modifiers.add(ModuleDescriptor.Modifier.OPEN); 350 if ((module_flags & ACC_SYNTHETIC) != 0) 409 int exports_index = in.readUnsignedShort(); 410 String pkg = cpool.getPackageName(exports_index); 411 412 Set<Exports.Modifier> mods; 413 int exports_flags = in.readUnsignedShort(); 414 if (exports_flags == 0) { 415 mods = Collections.emptySet(); 416 } else { 417 mods = new HashSet<>(); 418 if ((exports_flags & ACC_SYNTHETIC) != 0) 419 mods.add(Exports.Modifier.SYNTHETIC); 420 if ((exports_flags & ACC_MANDATED) != 0) 421 mods.add(Exports.Modifier.MANDATED); 422 } 423 424 int exports_to_count = in.readUnsignedShort(); 425 if (exports_to_count > 0) { 426 Set<String> targets = new HashSet<>(exports_to_count); 427 for (int j=0; j<exports_to_count; j++) { 428 int exports_to_index = in.readUnsignedShort(); 429 String target = cpool.getModuleName(exports_to_index); 430 if (!targets.add(target)) { 431 throw invalidModuleDescriptor(pkg + " exported to " 432 + target + " more than once"); 433 } 434 } 435 builder.exports(mods, pkg, targets); 436 } else { 437 builder.exports(mods, pkg); 438 } 439 } 440 } 441 442 int opens_count = in.readUnsignedShort(); 443 if (opens_count > 0) { 444 if (open) { 445 throw invalidModuleDescriptor("The opens table for an open" 446 + " module must be 0 length"); 447 } 448 for (int i=0; i<opens_count; i++) { 449 int opens_index = in.readUnsignedShort(); 450 String pkg = cpool.getPackageName(opens_index); 451 452 Set<Opens.Modifier> mods; 453 int opens_flags = in.readUnsignedShort(); 454 if (opens_flags == 0) { 455 mods = Collections.emptySet(); 456 } else { 457 mods = new HashSet<>(); 458 if ((opens_flags & ACC_SYNTHETIC) != 0) 459 mods.add(Opens.Modifier.SYNTHETIC); 460 if ((opens_flags & ACC_MANDATED) != 0) 461 mods.add(Opens.Modifier.MANDATED); 462 } 463 464 int open_to_count = in.readUnsignedShort(); 465 if (open_to_count > 0) { 466 Set<String> targets = new HashSet<>(open_to_count); 467 for (int j=0; j<open_to_count; j++) { 468 int opens_to_index = in.readUnsignedShort(); 469 String target = cpool.getModuleName(opens_to_index); 470 if (!targets.add(target)) { 471 throw invalidModuleDescriptor(pkg + " opened to " 472 + target + " more than once"); 473 } 474 } 475 builder.opens(mods, pkg, targets); 476 } else { 477 builder.opens(mods, pkg); 478 } 479 } 480 } 481 482 int uses_count = in.readUnsignedShort(); 483 if (uses_count > 0) { 484 for (int i=0; i<uses_count; i++) { 485 int index = in.readUnsignedShort(); 486 String sn = cpool.getClassName(index); 487 builder.uses(sn); 488 } 489 } 490 491 int provides_count = in.readUnsignedShort(); 492 if (provides_count > 0) { 493 for (int i=0; i<provides_count; i++) { 494 int index = in.readUnsignedShort(); 495 String sn = cpool.getClassName(index); 496 int with_count = in.readUnsignedShort(); 497 List<String> providers = new ArrayList<>(with_count); 498 for (int j=0; j<with_count; j++) { 499 index = in.readUnsignedShort(); 500 String pn = cpool.getClassName(index); 501 if (!providers.add(pn)) { 502 throw invalidModuleDescriptor(sn + " provides " + pn 503 + " more than once"); 504 } 505 } 506 builder.provides(sn, providers); 507 } 508 } 509 510 return builder; 511 } 512 513 /** 514 * Reads the ModulePackages attribute 515 */ 516 private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool) 517 throws IOException 518 { 519 int package_count = in.readUnsignedShort(); 520 Set<String> packages = new HashSet<>(package_count); 521 for (int i=0; i<package_count; i++) { 522 int index = in.readUnsignedShort(); 523 String pn = cpool.getPackageName(index); 524 boolean added = packages.add(pn); 526 throw invalidModuleDescriptor("Package " + pn + " in ModulePackages" 527 + "attribute more than once"); 528 } 529 } 530 return packages; 531 } 532 533 /** 534 * Reads the ModuleMainClass attribute 535 */ 536 private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool) 537 throws IOException 538 { 539 int index = in.readUnsignedShort(); 540 return cpool.getClassName(index); 541 } 542 543 /** 544 * Reads the ModuleTarget attribute 545 */ 546 private ModuleTarget readModuleTargetAttribute(DataInput in, ConstantPool cpool) 547 throws IOException 548 { 549 String osName = null; 550 String osArch = null; 551 552 int name_index = in.readUnsignedShort(); 553 if (name_index != 0) 554 osName = cpool.getUtf8(name_index); 555 556 int arch_index = in.readUnsignedShort(); 557 if (arch_index != 0) 558 osArch = cpool.getUtf8(arch_index); 559 560 return new ModuleTarget(osName, osArch); 561 } 562 563 564 /** 565 * Reads the ModuleHashes attribute 566 */ 567 private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool) 568 throws IOException 569 { 570 int algorithm_index = in.readUnsignedShort(); 571 String algorithm = cpool.getUtf8(algorithm_index); 572 573 int hash_count = in.readUnsignedShort(); 574 Map<String, byte[]> map = new HashMap<>(hash_count); 575 for (int i=0; i<hash_count; i++) { 576 int module_name_index = in.readUnsignedShort(); 577 String mn = cpool.getModuleName(module_name_index); 578 int hash_length = in.readUnsignedShort(); 579 if (hash_length == 0) { 580 throw invalidModuleDescriptor("hash_length == 0"); |