1 /* 2 * Copyright (c) 1999, 2016, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.tools.javac.jvm; 26 27 import com.sun.tools.javac.util.ByteBuffer; 28 import com.sun.tools.javac.util.Name.NameMapper; 29 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.nio.file.Files; 33 import java.nio.file.Path; 34 35 import javax.tools.JavaFileObject; 36 37 import static com.sun.tools.javac.jvm.ClassFile.*; 38 39 40 /** 41 * Stripped down ClassReader, just sufficient to read module names from module-info.class files 42 * while analyzing the module path. 43 * 44 * <p> 45 * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at 46 * your own risk. This code and its internal interfaces are subject to change or deletion without 47 * notice.</b> 48 */ 49 public class ModuleNameReader { 50 public static class BadClassFile extends Exception { 51 private static final long serialVersionUID = 0; 52 BadClassFile(String msg) { 53 super(msg); 54 } 55 } 56 57 private static final int INITIAL_BUFFER_SIZE = 0x0fff0; 58 59 /** The buffer containing the currently read class file. 60 */ 61 private ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE); 62 63 /** The current input pointer. 64 */ 65 private int bp; 66 67 /** The constant pool reader. 68 */ 69 private PoolReader reader; 70 71 public ModuleNameReader() { 72 } 73 74 public String readModuleName(Path p) throws IOException, BadClassFile { 75 try (InputStream in = Files.newInputStream(p)) { 76 return readModuleName(in); 77 } 78 } 79 80 public String readModuleName(JavaFileObject jfo) throws IOException, BadClassFile { 81 try (InputStream in = jfo.openInputStream()) { 82 return readModuleName(in); 83 } 84 } 85 86 public String readModuleName(InputStream in) throws IOException, BadClassFile { 87 bp = 0; 88 buf.reset(); 89 buf.appendStream(in); 90 91 int magic = nextInt(); 92 if (magic != JAVA_MAGIC) 93 throw new BadClassFile("illegal.start.of.class.file"); 94 95 int minorVersion = nextChar(); 96 int majorVersion = nextChar(); 97 if (majorVersion < 53) 98 throw new BadClassFile("bad major version number for module: " + majorVersion); 99 100 reader = new PoolReader(buf); 101 bp = reader.readPool(buf, bp); 102 103 int access_flags = nextChar(); 104 if (access_flags != 0x8000) 105 throw new BadClassFile("invalid access flags for module: 0x" + Integer.toHexString(access_flags)); 106 107 int this_class = nextChar(); 108 // could, should, check this_class == CONSTANT_Class("module-info") 109 checkZero(nextChar(), "super_class"); 110 checkZero(nextChar(), "interface_count"); 111 checkZero(nextChar(), "fields_count"); 112 checkZero(nextChar(), "methods_count"); 113 int attributes_count = nextChar(); 114 for (int i = 0; i < attributes_count; i++) { 115 int attr_name = nextChar(); 116 int attr_length = nextInt(); 117 if (reader.peekName(attr_name, utf8Mapper(false)).equals("Module") && attr_length > 2) { 118 return reader.peekModuleName(nextChar(), utf8Mapper(true)); 119 } else { 120 // skip over unknown attributes 121 bp += attr_length; 122 } 123 } 124 throw new BadClassFile("no Module attribute"); 125 } 126 127 void checkZero(int count, String name) throws BadClassFile { 128 if (count != 0) 129 throw new BadClassFile("invalid " + name + " for module: " + count); 130 } 131 132 /** Read a character. 133 */ 134 char nextChar() { 135 char res = buf.getChar(bp); 136 bp += 2; 137 return res; 138 } 139 140 /** Read an integer. 141 */ 142 int nextInt() { 143 int res = buf.getInt(bp); 144 bp += 4; 145 return res; 146 } 147 148 NameMapper<String> utf8Mapper(boolean internalize) { 149 return internalize ? 150 (buf, offset, len) -> new String(ClassFile.internalize(buf, offset, len)) : 151 String::new; 152 } 153 154 }