All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.java.decompiler.struct.attr.StructModuleAttribute Maven / Gradle / Ivy

Go to download

Modern Java & JVM language decompiler aiming to be as accurate as possible, with an emphasis on output quality.

The newest version!
// 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.code.BytecodeVersion;
import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
import org.jetbrains.java.decompiler.util.DataInputFullStream;

import java.io.IOException;
import java.lang.module.ModuleDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

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, BytecodeVersion version) 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 ModuleDescriptor asDescriptor() {
    var mods = EnumSet.noneOf(ModuleDescriptor.Modifier.class);
    if ((this.moduleFlags & CodeConstants.ACC_OPEN) != 0) mods.add(ModuleDescriptor.Modifier.OPEN);
    if ((this.moduleFlags & CodeConstants.ACC_SYNTHETIC) != 0) mods.add(ModuleDescriptor.Modifier.SYNTHETIC);
    if ((this.moduleFlags & CodeConstants.ACC_MANDATED) != 0) mods.add(ModuleDescriptor.Modifier.MANDATED);

    var builder = ModuleDescriptor.newModule(this.moduleName, mods);
    if (moduleVersion != null) builder.version(moduleVersion);

    for (final var requires : this.requires) {
      var rMods = EnumSet.noneOf(ModuleDescriptor.Requires.Modifier.class);
      if ((requires.flags & CodeConstants.ACC_TRANSITIVE) != 0) rMods.add(ModuleDescriptor.Requires.Modifier.TRANSITIVE);
      if ((requires.flags & CodeConstants.ACC_STATIC_PHASE) != 0) rMods.add(ModuleDescriptor.Requires.Modifier.STATIC);
      if ((requires.flags & CodeConstants.ACC_SYNTHETIC) != 0) rMods.add(ModuleDescriptor.Requires.Modifier.SYNTHETIC);
      if ((requires.flags & CodeConstants.ACC_MANDATED) != 0) rMods.add(ModuleDescriptor.Requires.Modifier.MANDATED);
      if (requires.moduleVersion != null) {
        builder.requires(rMods, requires.moduleName, ModuleDescriptor.Version.parse(requires.moduleVersion));
      } else {
        builder.requires(rMods, requires.moduleName);
      }
    }

    for (final var exports : this.exports) {
      var eMods = EnumSet.noneOf(ModuleDescriptor.Exports.Modifier.class);
      if ((exports.flags & CodeConstants.ACC_SYNTHETIC) != 0) eMods.add(ModuleDescriptor.Exports.Modifier.SYNTHETIC);
      if ((exports.flags & CodeConstants.ACC_MANDATED) != 0) eMods.add(ModuleDescriptor.Exports.Modifier.MANDATED);
      if (exports.exportToModules.isEmpty()) {
        builder.exports(eMods, exports.packageName.replace('/', '.'));
      } else {
        builder.exports(eMods, exports.packageName.replace('/', '.'), Set.copyOf(exports.exportToModules));
      }
    }

    for (final var opens : this.opens) {
      var oMods = EnumSet.noneOf(ModuleDescriptor.Opens.Modifier.class);
      if ((opens.flags & CodeConstants.ACC_SYNTHETIC) != 0) oMods.add(ModuleDescriptor.Opens.Modifier.SYNTHETIC);
      if ((opens.flags & CodeConstants.ACC_MANDATED) != 0) oMods.add(ModuleDescriptor.Opens.Modifier.MANDATED);

      if (opens.opensToModules.isEmpty()) {
        builder.opens(oMods, opens.packageName.replace('/', '.'));
      } else {
        builder.opens(oMods, opens.packageName.replace('/', '.'), Set.copyOf(opens.opensToModules));
      }
    }

    for (final var uses : this.uses) {
      builder.uses(uses.replace('/', '.'));
    }

    for (final var provides : this.provides) {
      builder.provides(
        provides.interfaceName.replace('/', '.'),
        provides.implementationNames.stream().map(name -> name.replace('/', '.')).collect(Collectors.toUnmodifiableList())
      );
    }

    return builder.build();
  }

  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;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy