diff options
Diffstat (limited to 'dx/src/com/android/dx/command/dump/BaseDumper.java')
-rw-r--r-- | dx/src/com/android/dx/command/dump/BaseDumper.java | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/dx/src/com/android/dx/command/dump/BaseDumper.java b/dx/src/com/android/dx/command/dump/BaseDumper.java new file mode 100644 index 0000000..ad6540b --- /dev/null +++ b/dx/src/com/android/dx/command/dump/BaseDumper.java @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed 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 com.android.dx.command.dump; + +import com.android.dx.cf.code.ConcreteMethod; +import com.android.dx.cf.iface.Member; +import com.android.dx.cf.iface.ParseObserver; +import com.android.dx.rop.code.AccessFlags; +import com.android.dx.util.ByteArray; +import com.android.dx.util.Hex; +import com.android.dx.util.IndentingWriter; +import com.android.dx.util.TwoColumnOutput; + +import java.io.IOException; +import java.io.PrintStream; +import java.io.StringWriter; + +/** + * Base class for the various human-friendly dumpers. + */ +public abstract class BaseDumper + implements ParseObserver { + /** {@code non-null;} array of data being dumped */ + private final byte[] bytes; + + /** whether or not to include the raw bytes (in a column on the left) */ + private final boolean rawBytes; + + /** {@code non-null;} where to dump to */ + private final PrintStream out; + + /** width of the output in columns */ + private final int width; + + /** + * {@code non-null;} the file path for the class, excluding any base + * directory specification + */ + private final String filePath; + + /** whether to be strict about parsing */ + private final boolean strictParse; + + /** number of bytes per line in hex dumps */ + private final int hexCols; + + /** the current level of indentation */ + private int indent; + + /** {@code non-null;} the current column separator string */ + private String separator; + + /** the offset of the next byte to dump */ + private int at; + + /** commandline parsedArgs */ + protected Args args; + + /** + * Constructs an instance. + * + * @param bytes {@code non-null;} bytes of the (alleged) class file + * on the left) + * @param out {@code non-null;} where to dump to + * @param filePath the file path for the class, excluding any base + * directory specification + */ + public BaseDumper(byte[] bytes, PrintStream out, + String filePath, Args args) { + this.bytes = bytes; + this.rawBytes = args.rawBytes; + this.out = out; + this.width = (args.width <= 0) ? 79 : args.width; + this.filePath = filePath; + this.strictParse = args.strictParse; + this.indent = 0; + this.separator = rawBytes ? "|" : ""; + this.at = 0; + this.args = args; + + int hexCols = (((width - 5) / 15) + 1) & ~1; + if (hexCols < 6) { + hexCols = 6; + } else if (hexCols > 10) { + hexCols = 10; + } + this.hexCols = hexCols; + } + + /** + * Computes the total width, in register-units, of the parameters for + * this method. + * @param meth method to process + * @return width in register-units + */ + static int computeParamWidth(ConcreteMethod meth, boolean isStatic) { + return meth.getEffectiveDescriptor().getParameterTypes(). + getWordCount(); + } + + /** {@inheritDoc} */ + public void changeIndent(int indentDelta) { + indent += indentDelta; + + separator = rawBytes ? "|" : ""; + for (int i = 0; i < indent; i++) { + separator += " "; + } + } + + /** {@inheritDoc} */ + public void parsed(ByteArray bytes, int offset, int len, String human) { + offset = bytes.underlyingOffset(offset, getBytes()); + + boolean rawBytes = getRawBytes(); + + if (offset < at) { + println("<dump skipped backwards to " + Hex.u4(offset) + ">"); + at = offset; + } else if (offset > at) { + String hex = rawBytes ? hexDump(at, offset - at) : ""; + print(twoColumns(hex, "<skipped to " + Hex.u4(offset) + ">")); + at = offset; + } + + String hex = rawBytes ? hexDump(offset, len) : ""; + print(twoColumns(hex, human)); + at += len; + } + + /** {@inheritDoc} */ + public void startParsingMember(ByteArray bytes, int offset, String name, + String descriptor) { + // This space intentionally left blank. + } + + /** {@inheritDoc} */ + public void endParsingMember(ByteArray bytes, int offset, String name, + String descriptor, Member member) { + // This space intentionally left blank. + } + + /** + * Gets the current dump cursor (that is, the offset of the expected + * next byte to dump). + * + * @return {@code >= 0;} the dump cursor + */ + protected final int getAt() { + return at; + } + + /** + * Sets the dump cursor to the indicated offset in the given array. + * + * @param arr {@code non-null;} array in question + * @param offset {@code >= 0;} offset into the array + */ + protected final void setAt(ByteArray arr, int offset) { + at = arr.underlyingOffset(offset, bytes); + } + + /** + * Gets the array of {@code byte}s to process. + * + * @return {@code non-null;} the bytes + */ + protected final byte[] getBytes() { + return bytes; + } + + /** + * Gets the filesystem/jar path of the file being dumped. + * + * @return {@code non-null;} the path + */ + protected final String getFilePath() { + return filePath; + } + + /** + * Gets whether to be strict about parsing. + * + * @return whether to be strict about parsing + */ + protected final boolean getStrictParse() { + return strictParse; + } + + /** + * Prints the given string to this instance's output stream. + * + * @param s {@code null-ok;} string to print + */ + protected final void print(String s) { + out.print(s); + } + + /** + * Prints the given string to this instance's output stream, followed + * by a newline. + * + * @param s {@code null-ok;} string to print + */ + protected final void println(String s) { + out.println(s); + } + + /** + * Gets whether this dump is to include raw bytes. + * + * @return the raw bytes flag + */ + protected final boolean getRawBytes() { + return rawBytes; + } + + /** + * Gets the width of the first column of output. This is {@code 0} + * unless raw bytes are being included in the output. + * + * @return {@code >= 0;} the width of the first column + */ + protected final int getWidth1() { + if (rawBytes) { + return 5 + (hexCols * 2) + (hexCols / 2); + } + + return 0; + } + + /** + * Gets the width of the second column of output. + * + * @return {@code >= 0;} the width of the second column + */ + protected final int getWidth2() { + int w1 = rawBytes ? (getWidth1() + 1) : 0; + return width - w1 - (indent * 2); + } + + /** + * Constructs a hex data dump of the given portion of {@link #bytes}. + * + * @param offset offset to start dumping at + * @param len length to dump + * @return {@code non-null;} the dump + */ + protected final String hexDump(int offset, int len) { + return Hex.dump(bytes, offset, len, offset, hexCols, 4); + } + + /** + * Combines a pair of strings as two columns, or if this is one-column + * output, format the otherwise-second column. + * + * @param s1 {@code non-null;} the first column's string + * @param s2 {@code non-null;} the second column's string + * @return {@code non-null;} the combined output + */ + protected final String twoColumns(String s1, String s2) { + int w1 = getWidth1(); + int w2 = getWidth2(); + + try { + if (w1 == 0) { + int len2 = s2.length(); + StringWriter sw = new StringWriter(len2 * 2); + IndentingWriter iw = new IndentingWriter(sw, w2, separator); + + iw.write(s2); + if ((len2 == 0) || (s2.charAt(len2 - 1) != '\n')) { + iw.write('\n'); + } + iw.flush(); + + return sw.toString(); + } else { + return TwoColumnOutput.toString(s1, w1, separator, s2, w2); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } +} |