// 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 requiresFlags = 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, requiresFlags, version)); } return requires; } private static 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(); List exportsToModules = readStringList(data, pool); String packageName = pool.getPrimitiveConstant(packageNameIndex).getString(); exports.add(new ExportsEntry(packageName, exportsFlags, exportsToModules)); } return exports; } private static 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(); List opensToModules = readStringList(data, pool); String packageName = pool.getPrimitiveConstant(packageNameIndex).getString(); opens.add(new OpensEntry(packageName, opensFlags, opensToModules)); } return opens; } private static List readUses(DataInputFullStream data, ConstantPool pool) throws IOException { return readStringList(data, pool); } private static 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(); List implementationNames = readStringList(data, pool); provides.add(new ProvidesEntry(interfaceName, implementationNames)); } return provides; } private static List readStringList(DataInputFullStream data, ConstantPool pool) throws IOException { int count = data.readUnsignedShort(); if (count <= 0) { return Collections.emptyList(); } else { List strings = new ArrayList<>(count); for (int i = 0; i < count; i++) { int index = data.readUnsignedShort(); strings.add(pool.getPrimitiveConstant(index).getString()); } return strings; } } public static final class RequiresEntry { public final String moduleName; public final int flags; public final String moduleVersion; public RequiresEntry(String moduleName, int flags, String moduleVersion) { this.moduleName = moduleName; this.flags = flags; this.moduleVersion = moduleVersion; } } public static final class ExportsEntry { public final String packageName; public final int flags; public final List exportToModules; public ExportsEntry(String packageName, int flags, List exportToModules) { this.packageName = packageName; this.flags = flags; this.exportToModules = exportToModules; } } public static final class OpensEntry { public final String packageName; public final int flags; public final List opensToModules; public OpensEntry(String packageName, int flags, List exportToModules) { this.packageName = packageName; this.flags = flags; this.opensToModules = exportToModules; } } public static final class ProvidesEntry { public final String interfaceName; public final List implementationNames; public ProvidesEntry(String interfaceName, List implementationNames) { this.interfaceName = interfaceName; this.implementationNames = implementationNames; } } }