BaseDumper.java revision de75089fb7216d19e9c22cce4dc62a49513477d3
1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.command.dump;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.code.ConcreteMethod;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.Member;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseObserver;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.AccessFlags;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.ByteArray;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.IndentingWriter;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.TwoColumnOutput;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.PrintStream;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.StringWriter;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Base class for the various human-friendly dumpers.
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic abstract class BaseDumper
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        implements ParseObserver {
3799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} array of data being dumped */
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final byte[] bytes;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** whether or not to include the raw bytes (in a column on the left) */
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final boolean rawBytes;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} where to dump to */
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final PrintStream out;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** width of the output in columns */
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int width;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
5099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} the file path for the class, excluding any base
51de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     * directory specification
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final String filePath;
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** whether to be strict about parsing */
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final boolean strictParse;
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     /** number of bytes per line in hex dumps */
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int hexCols;
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** the current level of indentation */
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int indent;
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
6499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} the current column separator string */
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private String separator;
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** the offset of the next byte to dump */
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int at;
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** commandline parsedArgs */
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected Args args;
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance.
75de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
7699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} bytes of the (alleged) class file
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * on the left)
7899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} where to dump to
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param filePath the file path for the class, excluding any base
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * directory specification
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public BaseDumper(byte[] bytes, PrintStream out,
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                      String filePath, Args args) {
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.bytes = bytes;
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.rawBytes = args.rawBytes;
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.out = out;
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.width = (args.width <= 0) ? 79 : args.width;
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.filePath = filePath;
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.strictParse = args.strictParse;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.indent = 0;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.separator = rawBytes ? "|" : "";
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.at = 0;
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.args = args;
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int hexCols = (((width - 5) / 15) + 1) & ~1;
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (hexCols < 6) {
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hexCols = 6;
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (hexCols > 10) {
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hexCols = 10;
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.hexCols = hexCols;
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Computes the total width, in register-units, of the parameters for
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * this method.
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param meth method to process
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return width in register-units
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    static int computeParamWidth(ConcreteMethod meth, boolean isStatic) {
11199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return meth.getEffectiveDescriptor().getParameterTypes().
11299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            getWordCount();
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void changeIndent(int indentDelta) {
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        indent += indentDelta;
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        separator = rawBytes ? "|" : "";
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < indent; i++) {
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            separator += "  ";
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void parsed(ByteArray bytes, int offset, int len, String human) {
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        offset = bytes.underlyingOffset(offset, getBytes());
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean rawBytes = getRawBytes();
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (offset < at) {
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            println("<dump skipped backwards to " + Hex.u4(offset) + ">");
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            at = offset;
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (offset > at) {
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String hex = rawBytes ? hexDump(at, offset - at) : "";
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            print(twoColumns(hex, "<skipped to " + Hex.u4(offset) + ">"));
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            at = offset;
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String hex = rawBytes ? hexDump(offset, len) : "";
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        print(twoColumns(hex, human));
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        at += len;
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void startParsingMember(ByteArray bytes, int offset, String name,
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                   String descriptor) {
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void endParsingMember(ByteArray bytes, int offset, String name,
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                 String descriptor, Member member) {
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the current dump cursor (that is, the offset of the expected
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * next byte to dump).
160de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
16199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the dump cursor
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final int getAt() {
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return at;
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Sets the dump cursor to the indicated offset in the given array.
169de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
17099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param arr {@code non-null;} array in question
17199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param offset {@code >= 0;} offset into the array
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final void setAt(ByteArray arr, int offset) {
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        at = arr.underlyingOffset(offset, bytes);
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
17899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Gets the array of {@code byte}s to process.
179de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
18099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the bytes
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final byte[] getBytes() {
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return bytes;
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the filesystem/jar path of the file being dumped.
188de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
18999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the path
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final String getFilePath() {
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return filePath;
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets whether to be strict about parsing.
197de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether to be strict about parsing
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final boolean getStrictParse() {
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return strictParse;
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Prints the given string to this instance's output stream.
206de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
20799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param s {@code null-ok;} string to print
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final void print(String s) {
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.print(s);
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Prints the given string to this instance's output stream, followed
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * by a newline.
216de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
21799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param s {@code null-ok;} string to print
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final void println(String s) {
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.println(s);
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets whether this dump is to include raw bytes.
225de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the raw bytes flag
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final boolean getRawBytes() {
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return rawBytes;
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
23399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Gets the width of the first column of output. This is {@code 0}
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * unless raw bytes are being included in the output.
235de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
23699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the width of the first column
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final int getWidth1() {
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (rawBytes) {
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 5 + (hexCols * 2) + (hexCols / 2);
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return 0;
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the width of the second column of output.
248de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
24999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the width of the second column
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final int getWidth2() {
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int w1 = rawBytes ? (getWidth1() + 1) : 0;
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return width - w1 - (indent * 2);
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs a hex data dump of the given portion of {@link #bytes}.
258de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param offset offset to start dumping at
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param len length to dump
26199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the dump
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final String hexDump(int offset, int len) {
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return Hex.dump(bytes, offset, len, offset, hexCols, 4);
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Combines a pair of strings as two columns, or if this is one-column
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * output, format the otherwise-second column.
270de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
27199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param s1 {@code non-null;} the first column's string
27299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param s2 {@code non-null;} the second column's string
27399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the combined output
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected final String twoColumns(String s1, String s2) {
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int w1 = getWidth1();
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int w2 = getWidth2();
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (w1 == 0) {
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int len2 = s2.length();
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                StringWriter sw = new StringWriter(len2 * 2);
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                IndentingWriter iw = new IndentingWriter(sw, w2, separator);
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                iw.write(s2);
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if ((len2 == 0) || (s2.charAt(len2 - 1) != '\n')) {
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    iw.write('\n');
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                iw.flush();
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return sw.toString();
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return TwoColumnOutput.toString(s1, w1, separator, s2, w2);
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IOException ex) {
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new RuntimeException(ex);
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
300