1 /*
  2  * Copyright (c) 2016, 2020, 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.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.asmtools.jdis;
 24 
 25 import java.io.DataInputStream;
 26 import java.io.IOException;
 27 import java.io.PrintWriter;
 28 import java.util.*;
 29 
 30 import org.openjdk.asmtools.common.Module;
 31 import org.openjdk.asmtools.common.Tool;
 32 import org.openjdk.asmtools.jasm.JasmTokens;
 33 
 34 import static org.openjdk.asmtools.jdis.Main.i18n;
 35 
 36 /**
 37  *  The module attribute data.
 38  */
 39 public class ModuleData {
 40 
 41   // internal references
 42   private final Tool tool;
 43 
 44   private ConstantPool pool;
 45   private PrintWriter out;
 46   private Module module;
 47 
 48   public ModuleData(ClassData clsData) {
 49     this.tool = clsData.tool;
 50     this.pool = clsData.pool;
 51     this.out = clsData.out;
 52   }
 53 
 54   public String getModuleName() {
 55     return module == null ? "N/A" : module.getModuleName();
 56   }
 57 
 58   public String getModuleVersion() { return module.getModuleVersion();  }
 59 
 60   public String getModuleHeader() {
 61     if ( module == null ) {
 62       return "N/A";
 63     } else {
 64       StringBuilder sb = new StringBuilder(module.getModuleFlags());
 65       sb.append(JasmTokens.Token.MODULE.parseKey()).append(" ");
 66       sb.append(module.getModuleName());
 67       if (module.getModuleVersion() != null)
 68         sb.append("// @").append(module.getModuleVersion());
 69       return sb.toString();
 70     }
 71   }
 72 
 73   /**
 74    * Reads and resolve the method's attribute data called from ClassData.
 75    */
 76   public void read(DataInputStream in) throws IOException {
 77     int index, moduleFlags, versionIndex;
 78     String moduleName, version;
 79     Module.Builder builder;
 80     try {
 81     // u2 module_name_index;
 82     index = in.readUnsignedShort();
 83     moduleName = pool.getModule(index);
 84     // u2 module_flags;
 85     moduleFlags = in.readUnsignedShort();
 86     // u2 module_version_index;
 87     versionIndex = in.readUnsignedShort();
 88     version = pool.getString(versionIndex);
 89     builder = new Module.Builder(moduleName, moduleFlags, version);
 90     } catch (IOException ioe) {
 91       tool.error(i18n.getString("jdis.error.invalid_header"));
 92       throw ioe;
 93     }
 94 
 95     try {
 96       int requires_count = in.readUnsignedShort();
 97       for (int i = 0; i < requires_count; i++) {
 98         index = in.readUnsignedShort();
 99         int requiresFlags = in.readUnsignedShort();
100         versionIndex = in.readUnsignedShort();
101 
102         moduleName = pool.getModule(index);
103         version = pool.getString(versionIndex);
104         builder.require(moduleName, requiresFlags, version);
105       }
106     } catch (IOException ioe) {
107       tool.error(i18n.getString("jdis.error.invalid_requires"));
108       throw ioe;
109     }
110 
111     try {
112       int exports_count = in.readUnsignedShort();
113       if (exports_count > 0) {
114         for (int i = 0; i < exports_count; i++) {
115           index = in.readUnsignedShort();
116           String packageName = pool.getPackage(index);
117           int exportsFlags = in.readUnsignedShort();
118           int exports_to_count = in.readUnsignedShort();
119           if (exports_to_count > 0) {
120             Set<String> targets = new HashSet<>(exports_to_count);
121             for (int j = 0; j < exports_to_count; j++) {
122               int exports_to_index = in.readUnsignedShort();
123               targets.add(pool.getModule(exports_to_index));
124             }
125             builder.exports(packageName, exportsFlags, targets);
126           } else {
127             builder.exports(packageName, exportsFlags);
128           }
129         }
130       }
131     } catch (IOException ioe) {
132       tool.error(i18n.getString("jdis.error.invalid_exports"));
133       throw ioe;
134     }
135 
136     try {
137       int opens_count = in.readUnsignedShort();
138       if (opens_count > 0) {
139         for (int i = 0; i < opens_count; i++) {
140           index = in.readUnsignedShort();
141           String packageName = pool.getPackage(index);
142           int opensFlags = in.readUnsignedShort();
143           int opens_to_count = in.readUnsignedShort();
144           if (opens_to_count > 0) {
145             Set<String> targets = new HashSet<>(opens_to_count);
146             for (int j = 0; j < opens_to_count; j++) {
147               int opens_to_index = in.readUnsignedShort();
148               targets.add(pool.getModule(opens_to_index));
149             }
150             builder.opens(packageName, opensFlags, targets);
151           } else {
152             builder.opens(packageName, opensFlags);
153           }
154         }
155       }
156     } catch (IOException ioe) {
157       tool.error(i18n.getString("jdis.error.invalid_opens"));
158       throw ioe;
159     }
160 
161     try {
162       int uses_count = in.readUnsignedShort();
163       if (uses_count > 0) {
164         for (int i = 0; i < uses_count; i++) {
165           index = in.readUnsignedShort();
166           String serviceName = pool.getClassName(index);
167           builder.uses(serviceName);
168         }
169       }
170     } catch (IOException ioe) {
171       tool.error(i18n.getString("jdis.error.invalid_uses"));
172       throw ioe;
173     }
174 
175     try {
176       int provides_count = in.readUnsignedShort();
177       if (provides_count > 0) {
178         for (int i = 0; i < provides_count; i++) {
179           index = in.readUnsignedShort();
180           String serviceName = pool.getClassName(index);
181           int provides_with_count = in.readUnsignedShort();
182           Set<String> implNames = new HashSet<>(provides_with_count);
183           for (int j = 0; j < provides_with_count; j++) {
184             int provides_with_index = in.readUnsignedShort();
185             implNames.add(pool.getClassName(provides_with_index));
186           }
187           builder.provides(serviceName, implNames);
188         }
189       }
190     } catch (IOException ioe) {
191       tool.error(i18n.getString("jdis.error.invalid_provides"));
192       throw ioe;
193     }
194     module = builder.build();
195   }
196 
197   /* Print Methods */
198   public void print() {
199     if (module != null)
200       out.println(module.toString());
201   }
202 }