/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/ package org.apache.jasper.compiler;
/** * Contains static utilities for generating SMAP data based on the * current version of Jasper. * * @author Jayson Falkner * @author Shawn Bayern * @author Robert Field (inner SDEInstaller class) * @author Mark Roth * @author Kin-man Chung
*/ publicclass SmapUtil {
if (ctxt.getOptions().isSmapDumped()) {
File outSmap = new File(classFileName + ".smap");
PrintWriter so = new PrintWriter( new OutputStreamWriter( new FileOutputStream(outSmap),
SMAP_ENCODING));
so.print(s.getSmapString());
so.close();
}
if (ctxt.getOptions().isSmapDumped()) {
File outSmap = new File(innerClassFileName + ".smap");
PrintWriter so = new PrintWriter( new OutputStreamWriter( new FileOutputStream(outSmap),
SMAP_ENCODING));
so.print(s.getSmapString());
so.close();
}
}
this.sdeAttr = sdeAttr; // get the bytes
orig = readWhole(inClassFile);
gen = newbyte[orig.length + sdeAttr.length + 100];
}
void install(File outClassFile) throws IOException { // do it
addSDE();
// write result try (FileOutputStream outStream = new FileOutputStream(outClassFile)) {
outStream.write(gen, 0, genPos);
}
}
staticbyte[] readWhole(File input) throws IOException { int len = (int)input.length(); byte[] bytes = newbyte[len]; try (FileInputStream inStream = new FileInputStream(input)) { if (inStream.read(bytes, 0, len) != len) { thrownew IOException(Localizer.getMessage( "jsp.error.readContent", Integer.valueOf(len)));
}
} return bytes;
}
void addSDE() throws UnsupportedEncodingException, IOException {
copy(4 + 2 + 2); // magic min/maj version int constantPoolCountPos = genPos; int constantPoolCount = readU2(); if (log.isDebugEnabled()) {
log.debug("constant pool count: " + constantPoolCount);
}
writeU2(constantPoolCount);
// copy old constant pool return index of SDE symbol, if found
sdeIndex = copyConstantPool(constantPoolCount); if (sdeIndex < 0) { // if "SourceDebugExtension" symbol not there add it
writeUtf8ForSDE();
// increment the constantPoolCount
sdeIndex = constantPoolCount;
++constantPoolCount;
randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
if (log.isDebugEnabled()) {
log.debug("SourceDebugExtension not found, installed at: " + sdeIndex);
}
} else { if (log.isDebugEnabled()) {
log.debug("SourceDebugExtension found at: " + sdeIndex);
}
}
copy(2 + 2 + 2); // access, this, super int interfaceCount = readU2();
writeU2(interfaceCount); if (log.isDebugEnabled()) {
log.debug("interfaceCount: " + interfaceCount);
}
copy(interfaceCount * 2);
copyMembers(); // fields
copyMembers(); // methods int attrCountPos = genPos; int attrCount = readU2();
writeU2(attrCount); if (log.isDebugEnabled()) {
log.debug("class attrCount: " + attrCount);
} // copy the class attributes, return true if SDE attr found (not copied) if (!copyAttrs(attrCount)) { // we will be adding SDE and it isn't already counted
++attrCount;
randomAccessWriteU2(attrCountPos, attrCount); if (log.isDebugEnabled()) {
log.debug("class attrCount incremented");
}
}
writeAttrForSDE(sdeIndex);
}
void copyMembers() { int count = readU2();
writeU2(count); if (log.isDebugEnabled()) {
log.debug("members count: " + count);
} for (int i = 0; i < count; ++i) {
copy(6); // access, name, descriptor int attrCount = readU2();
writeU2(attrCount); if (log.isDebugEnabled()) {
log.debug("member attr count: " + attrCount);
}
copyAttrs(attrCount);
}
}
boolean copyAttrs(int attrCount) { boolean sdeFound = false; for (int i = 0; i < attrCount; ++i) { int nameIndex = readU2(); // don't write old SDE if (nameIndex == sdeIndex) {
sdeFound = true; if (log.isDebugEnabled()) {
log.debug("SDE attr found");
}
} else {
writeU2(nameIndex); // name int len = readU4();
writeU4(len);
copy(len); if (log.isDebugEnabled()) {
log.debug("attr len: " + len);
}
}
} return sdeFound;
}
void writeAttrForSDE(int index) {
writeU2(index);
writeU4(sdeAttr.length); for (byte b : sdeAttr) {
writeU1(b);
}
}
void randomAccessWriteU2(int pos, int val) { int savePos = genPos;
genPos = pos;
writeU2(val);
genPos = savePos;
}
int readU1() { return orig[origPos++] & 0xFF;
}
int readU2() { int res = readU1(); return (res << 8) + readU1();
}
int readU4() { int res = readU2(); return (res << 16) + readU2();
}
int copyConstantPool(int constantPoolCount) throws UnsupportedEncodingException, IOException { int sdeIndex = -1; // copy const pool index zero not in class file for (int i = 1; i < constantPoolCount; ++i) { int tag = readU1();
writeU1(tag); switch (tag) { case 7 : // Class case 8 : // String case 16 : // MethodType if (log.isDebugEnabled()) {
log.debug(i + " copying 2 bytes");
}
copy(2); break; case 15 : // MethodHandle if (log.isDebugEnabled()) {
log.debug(i + " copying 3 bytes");
}
copy(3); break; case 9 : // Field case 10 : // Method case 11 : // InterfaceMethod case 3 : // Integer case 4 : // Float case 12 : // NameAndType case 18 : // InvokeDynamic if (log.isDebugEnabled()) {
log.debug(i + " copying 4 bytes");
}
copy(4); break; case 5 : // Long case 6 : // Double if (log.isDebugEnabled()) {
log.debug(i + " copying 8 bytes");
}
copy(8);
i++; break; case 1 : // Utf8 int len = readU2();
writeU2(len); byte[] utf8 = readBytes(len);
String str = new String(utf8, "UTF-8"); if (log.isDebugEnabled()) {
log.debug(i + " read class attr -- '" + str + "'");
} if (str.equals(nameSDE)) {
sdeIndex = i;
}
writeBytes(utf8); break; default : thrownew IOException(Localizer.getMessage( "jsp.error.unexpectedTag", Integer.valueOf(tag)));
}
} return sdeIndex;
}
void writeUtf8ForSDE() { int len = nameSDE.length();
writeU1(1); // Utf8 tag
writeU2(len); for (int i = 0; i < len; ++i) {
writeU1(nameSDE.charAt(i));
}
}
}
@Override publicvoid visit(Node.TemplateText n) throws JasperException {
Mark mark = n.getStart(); if (mark == null) { return;
}
//Add the file information
String fileName = mark.getFile();
smap.addFile(unqualify(fileName), fileName);
//Add a LineInfo that corresponds to the beginning of this node int iInputStartLine = mark.getLineNumber(); int iOutputStartLine = n.getBeginJavaLine(); int iOutputLineIncrement = breakAtLF? 1: 0;
smap.addLineData(iInputStartLine, fileName, 1, iOutputStartLine,
iOutputLineIncrement);
// Output additional mappings in the text
java.util.ArrayList<Integer> extraSmap = n.getExtraSmap();
privatevoid doSmapText(Node n) {
String text = n.getText(); int index = 0; int next = 0; int lineCount = 1; int skippedLines = 0; boolean slashStarSeen = false; boolean beginning = true;
// Count lines inside text, but skipping comment lines at the // beginning of the text. while ((next = text.indexOf('\n', index)) > -1) { if (beginning) {
String line = text.substring(index, next).trim(); if (!slashStarSeen && line.startsWith("/*")) {
slashStarSeen = true;
} if (slashStarSeen) {
skippedLines++; int endIndex = line.indexOf("*/"); if (endIndex >= 0) { // End of /* */ comment
slashStarSeen = false; if (endIndex < line.length() - 2) { // Some executable code after comment
skippedLines--;
beginning = false;
}
}
} elseif (line.length() == 0 || line.startsWith("//")) {
skippedLines++;
} else {
beginning = false;
}
}
lineCount++;
index = next + 1;
}
publicstatic SmapStratum loadSmap(String className, ClassLoader cl) { // Extract SMAP from class file. First line "SMAP" is not included
String smap = getSmap(className, cl);
if (smap == null) { returnnull;
}
SmapStratum smapStratum = new SmapStratum();
String[] lines = smap.split("\n"); int lineIndex = 0;
// First line is output file name
smapStratum.setOutputFileName(lines[lineIndex]);
// There is only one stratum (JSP) so skip to the start of the file // section
lineIndex = 4;
while (!lines[lineIndex].equals("*L")) { int i = lines[lineIndex].lastIndexOf(' ');
String fileName = lines[lineIndex].substring(i + 1);
smapStratum.addFile(fileName, lines[++lineIndex]);
lineIndex++;
}
// Skip *L
lineIndex++;
while (!lines[lineIndex].equals("*E")) {
LineInfo li = new LineInfo(); // Split into in and out
String[] inOut = lines[lineIndex].split(":"); // Split in on comma (might not be one)
String[] in = inOut[0].split(","); if (in.length == 2) { // There is a count
li.setInputLineCount(Integer.parseInt(in[1]));
} // Check for fileID
String[] start = in[0].split("#"); if (start.length == 2) { // There is a file ID
li.setLineFileID(Integer.parseInt(start[1]));
}
li.setInputStartLine(Integer.parseInt(start[0])); // Split out
String[] out = inOut[1].split(","); if (out.length == 2) { // There is an increment
li.setOutputLineIncrement(Integer.parseInt(out[1]));
}
li.setOutputStartLine(Integer.parseInt(out[0]));
InputStream is = null; try {
is = cl.getResourceAsStream(className.replace(".","/") + ".smap"); if (is != null) {
encoding = SMAP_ENCODING;
found = true;
} else {
is = cl.getResourceAsStream(className.replace(".","/") + ".class"); // Alternative approach would be to read the class file as per the // JLS. That would require duplicating a lot of BCEL functionality. int b = is.read(); while (b != -1) { if (b == 'S') { if ((b = is.read()) != 'M') { continue;
} if ((b = is.read()) != 'A') { continue;
} if ((b = is.read()) != 'P') { continue;
} if ((b = is.read()) != '\n') { continue;
}
found = true; break;
}
b = is.read();
}
}
if (found) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); byte[] buf = newbyte[1024]; int numRead; while ( (numRead = is.read(buf) ) >= 0) {
baos.write(buf, 0, numRead);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.