1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2010 Ben Gruver
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29package org.jf.util;
30
31import java.io.IOException;
32import java.io.Writer;
33
34public class IndentingWriter extends Writer {
35    protected final Writer writer;
36    protected final char[] buffer = new char[24];
37    protected int indentLevel = 0;
38    private boolean beginningOfLine = true;
39    private static final String newLine = System.getProperty("line.separator");
40
41    public IndentingWriter(Writer writer) {
42        this.writer = writer;
43    }
44
45    protected void writeIndent() throws IOException {
46        for (int i=0; i<indentLevel; i++) {
47            writer.write(' ');
48        }
49    }
50
51    @Override
52    public void write(int chr) throws IOException {
53        if (chr == '\n') {
54            writer.write(newLine);
55            beginningOfLine = true;
56        } else {
57            if (beginningOfLine) {
58                writeIndent();
59            }
60            beginningOfLine = false;
61            writer.write(chr);
62        }
63    }
64
65    /**
66     * Writes out a block of text that contains no newlines
67     */
68    private void writeLine(char[] chars, int start, int len) throws IOException {
69        if (beginningOfLine && len > 0) {
70            writeIndent();
71            beginningOfLine = false;
72        }
73        writer.write(chars, start, len);
74    }
75
76
77    /**
78     * Writes out a block of text that contains no newlines
79     */
80    private void writeLine(String str, int start, int len) throws IOException {
81        if (beginningOfLine && len > 0) {
82            writeIndent();
83            beginningOfLine = false;
84        }
85        writer.write(str, start, len);
86    }
87
88    @Override
89    public void write(char[] chars) throws IOException {
90        write(chars, 0, chars.length);
91    }
92
93    @Override
94    public void write(char[] chars, int start, int len) throws IOException {
95        final int end = start+len;
96        int pos = start;
97        while (pos < end) {
98            if (chars[pos] == '\n') {
99                writeLine(chars, start, pos-start);
100
101                writer.write(newLine);
102                beginningOfLine = true;
103                pos++;
104                start = pos;
105            } else {
106                pos++;
107            }
108        }
109        writeLine(chars, start, pos-start);
110    }
111
112    @Override
113    public void write(String s) throws IOException {
114        write(s, 0, s.length());
115    }
116
117    @Override
118    public void write(String str, int start, int len) throws IOException {
119        final int end = start+len;
120        int pos = start;
121        while (pos < end) {
122            pos = str.indexOf('\n', start);
123            if (pos == -1) {
124                writeLine(str, start, end-start);
125                return;
126            } else {
127                writeLine(str, start, pos-start);
128                writer.write(newLine);
129                beginningOfLine = true;
130                start = pos+1;
131            }
132        }
133    }
134
135    @Override
136    public Writer append(CharSequence charSequence) throws IOException {
137        write(charSequence.toString());
138        return this;
139    }
140
141    @Override
142    public Writer append(CharSequence charSequence, int start, int len) throws IOException {
143        write(charSequence.subSequence(start, len).toString());
144        return this;
145    }
146
147    @Override
148    public Writer append(char c) throws IOException {
149        write(c);
150        return this;
151    }
152
153    @Override
154    public void flush() throws IOException {
155        writer.flush();
156    }
157
158    @Override
159    public void close() throws IOException {
160        writer.close();
161    }
162
163    public void indent(int indentAmount) {
164        this.indentLevel += indentAmount;
165        if (indentLevel < 0) {
166            indentLevel = 0;
167        }
168    }
169
170    public void deindent(int indentAmount) {
171        this.indentLevel -= indentAmount;
172        if (indentLevel < 0) {
173            indentLevel = 0;
174        }
175    }
176
177    public void printUnsignedLongAsHex(long value) throws IOException {
178        int bufferIndex = 23;
179        do {
180            int digit = (int)(value & 15);
181            if (digit < 10) {
182                buffer[bufferIndex--] = (char)(digit + '0');
183            } else {
184                buffer[bufferIndex--] = (char)((digit - 10) + 'a');
185            }
186
187            value >>>= 4;
188        } while (value != 0);
189
190        bufferIndex++;
191
192        writeLine(buffer, bufferIndex, 24-bufferIndex);
193    }
194
195    public void printSignedLongAsDec(long value) throws IOException {
196        int bufferIndex = 23;
197
198        if (value < 0) {
199            value *= -1;
200            write('-');
201        }
202
203        do {
204            long digit = value % 10;
205            buffer[bufferIndex--] = (char)(digit + '0');
206
207            value = value / 10;
208        } while (value != 0);
209
210        bufferIndex++;
211
212        writeLine(buffer, bufferIndex, 24-bufferIndex);
213    }
214
215    public void printSignedIntAsDec(int value) throws IOException {
216        int bufferIndex = 15;
217
218        if (value < 0) {
219            value *= -1;
220            write('-');
221        }
222
223        do {
224            int digit = value % 10;
225            buffer[bufferIndex--] = (char)(digit + '0');
226
227            value = value / 10;
228        } while (value != 0);
229
230        bufferIndex++;
231
232        writeLine(buffer, bufferIndex, 16-bufferIndex);
233    }
234
235    public void printUnsignedIntAsDec(int value) throws IOException {
236        int bufferIndex = 15;
237
238        if (value < 0) {
239            printSignedLongAsDec(value & 0xFFFFFFFFL);
240        } else {
241            printSignedIntAsDec(value);
242        }
243    }
244}
245