// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.struct.attr; import org.jetbrains.java.decompiler.struct.consts.ConstantPool; import org.jetbrains.java.decompiler.util.DataInputFullStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class StructModuleAttribute extends StructGeneralAttribute { public String moduleName; public int moduleFlags; public String moduleVersion; public List requires; public List exports; public List opens; public List uses; public List provides; @Override public void initContent(DataInputFullStream data, ConstantPool pool) throws IOException { int moduleNameIndex = data.readUnsignedShort(); this.moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString(); this.moduleFlags = data.readUnsignedShort(); int moduleVersionIndex = data.readUnsignedShort(); if (moduleVersionIndex != 0) { moduleVersion = pool.getPrimitiveConstant(moduleVersionIndex).getString(); } this.requires = readRequires(data, pool); this.exports = readExports(data, pool); this.opens = readOpens(data, pool); this.uses = readUses(data, pool); this.provides = readProvides(data, pool); } public List readRequires(DataInputFullStream data, ConstantPool pool) throws IOException { int requiresCount = data.readUnsignedShort(); if (requiresCount <= 0) { return Collections.emptyList(); } List requires = new ArrayList<>(requiresCount); for (int i = 0; i < requiresCount; i++) { int moduleNameIndex = data.readUnsignedShort(); int moduleFlags = data.readUnsignedShort(); int versionIndex = data.readUnsignedShort(); String moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString(); String version = versionIndex == 0 ? null : pool.getPrimitiveConstant(versionIndex).getString(); requires.add(new RequiresEntry(moduleName, moduleFlags, version)); } return requires; } private List readExports(DataInputFullStream data, ConstantPool pool) throws IOException { int exportsCount = data.readUnsignedShort(); if (exportsCount <= 0) { return Collections.emptyList(); } List exports = new ArrayList<>(exportsCount); for (int i = 0; i < exportsCount; i++) { int packageNameIndex = data.readUnsignedShort(); int exportsFlags = data.readUnsignedShort(); int exportsToCount = data.readUnsignedShort(); List exportsToModules; if (exportsToCount > 0) { exportsToModules = new ArrayList<>(exportsToCount); for (int j = 0; j < exportsToCount; j++) { int moduleNameIndex = data.readUnsignedShort(); String moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString(); exportsToModules.add(moduleName); } } else { exportsToModules = Collections.emptyList(); } String packageName = pool.getPrimitiveConstant(packageNameIndex).getString(); exports.add(new ExportsEntry(packageName, exportsFlags, exportsToModules)); } return exports; } private List readOpens(DataInputFullStream data, ConstantPool pool) throws IOException { int opensCount = data.readUnsignedShort(); if (opensCount <= 0) { return Collections.emptyList(); } List opens = new ArrayList<>(opensCount); for (int i = 0; i < opensCount; i++) { int packageNameIndex = data.readUnsignedShort(); int opensFlags = data.readUnsignedShort(); int opensToCount = data.readUnsignedShort(); List opensToModules; if (opensToCount > 0) { opensToModules = new ArrayList<>(opensToCount); for (int j = 0; j < opensToCount; j++) { int moduleNameIndex = data.readUnsignedShort(); String moduleName = pool.getPrimitiveConstant(moduleNameIndex).getString(); opensToModules.add(moduleName); } } else { opensToModules = Collections.emptyList(); } String packageName = pool.getPrimitiveConstant(packageNameIndex).getString(); opens.add(new OpensEntry(packageName, opensFlags, opensToModules)); } return opens; } private List readUses(DataInputFullStream data, ConstantPool pool) throws IOException { int usesCount = data.readUnsignedShort(); if (usesCount <= 0) { return Collections.emptyList(); } List uses = new ArrayList<>(usesCount); for (int i = 0; i < usesCount; i++) { int classNameIndex = data.readUnsignedShort(); String className = pool.getPrimitiveConstant(classNameIndex).getString(); uses.add(className); } return uses; } private List readProvides(DataInputFullStream data, ConstantPool pool) throws IOException { int providesCount = data.readUnsignedShort(); if (providesCount <= 0) { return Collections.emptyList(); } List provides = new ArrayList<>(providesCount); for (int i = 0; i < providesCount; i++) { int interfaceNameIndex = data.readUnsignedShort(); String interfaceName = pool.getPrimitiveConstant(interfaceNameIndex).getString(); // Always nonzero int providesWithCount = data.readUnsignedShort(); List implementationNames = new ArrayList<>(providesWithCount); for (int j = 0; j < providesWithCount; j++) { int classNameIndex = data.readUnsignedShort(); String className = pool.getPrimitiveConstant(classNameIndex).getString(); implementationNames.add(className); } provides.add(new ProvidesEntry(interfaceName, implementationNames)); } return provides; } public static final class RequiresEntry { public String moduleName; public int moduleFlags; public String moduleVersion; public RequiresEntry(String moduleName, int moduleFlags, String moduleVersion) { this.moduleName = moduleName; this.moduleFlags = moduleFlags; this.moduleVersion = moduleVersion; } } public static final class ExportsEntry { public String packageName; public int exportsFlags; public List exportToModules; public ExportsEntry(String packageName, int exportsFlags, List exportToModules) { this.packageName = packageName; this.exportsFlags = exportsFlags; this.exportToModules = exportToModules; } } public static final class OpensEntry { public String packageName; public int opensFlags; public List opensToModules; public OpensEntry(String packageName, int exportsFlags, List exportToModules) { this.packageName = packageName; this.opensFlags = exportsFlags; this.opensToModules = exportToModules; } } public static final class ProvidesEntry { public String interfaceName; public List implementationNames; public ProvidesEntry(String interfaceName, List implementationNames) { this.interfaceName = interfaceName; this.implementationNames = implementationNames; } } }