1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts2.interceptor.debugging;
22
23 import java.io.PrintWriter;
24 import java.io.Writer;
25 import java.util.Stack;
26
27 public class PrettyPrintWriter {
28
29 private final PrintWriter writer;
30 private final Stack<String> elementStack = new Stack<String>();
31 private final char[] lineIndenter;
32
33 private boolean tagInProgress;
34 private int depth;
35 private boolean readyForNewLine;
36 private boolean tagIsEmpty;
37 private String newLine;
38
39 private static final char[] NULL = "�".toCharArray();
40 private static final char[] AMP = "&".toCharArray();
41 private static final char[] LT = "<".toCharArray();
42 private static final char[] GT = ">".toCharArray();
43 private static final char[] SLASH_R = "
".toCharArray();
44 private static final char[] QUOT = """.toCharArray();
45 private static final char[] APOS = "'".toCharArray();
46 private static final char[] CLOSE = "</".toCharArray();
47
48 public PrettyPrintWriter(Writer writer, char[] lineIndenter, String newLine) {
49 this.writer = new PrintWriter(writer);
50 this.lineIndenter = lineIndenter;
51 this.newLine = newLine;
52 }
53
54 public PrettyPrintWriter(Writer writer, char[] lineIndenter) {
55 this(writer, lineIndenter, "\n");
56 }
57
58 public PrettyPrintWriter(Writer writer, String lineIndenter, String newLine) {
59 this(writer, lineIndenter.toCharArray(), newLine);
60 }
61
62 public PrettyPrintWriter(Writer writer, String lineIndenter) {
63 this(writer, lineIndenter.toCharArray());
64 }
65
66 public PrettyPrintWriter(Writer writer) {
67 this(writer, new char[]{' ', ' '});
68 }
69
70 public void startNode(String name) {
71 tagIsEmpty = false;
72 finishTag();
73 writer.write('<');
74 writer.write(name);
75 elementStack.push(name);
76 tagInProgress = true;
77 depth++;
78 readyForNewLine = true;
79 tagIsEmpty = true;
80 }
81
82 public void setValue(String text) {
83 readyForNewLine = false;
84 tagIsEmpty = false;
85 finishTag();
86
87 writeText(writer, text);
88 }
89
90 public void addAttribute(String key, String value) {
91 writer.write(' ');
92 writer.write(key);
93 writer.write('=');
94 writer.write('\"');
95 writeAttributeValue(writer, value);
96 writer.write('\"');
97 }
98
99 protected void writeAttributeValue(PrintWriter writer, String text) {
100 writeText(text);
101 }
102
103 protected void writeText(PrintWriter writer, String text) {
104 writeText(text);
105 }
106
107 private void writeText(String text) {
108 int length = text.length();
109 for (int i = 0; i < length; i++) {
110 char c = text.charAt(i);
111 switch (c) {
112 case '\0':
113 this.writer.write(NULL);
114 break;
115 case '&':
116 this.writer.write(AMP);
117 break;
118 case '<':
119 this.writer.write(LT);
120 break;
121 case '>':
122 this.writer.write(GT);
123 break;
124 case '"':
125 this.writer.write(QUOT);
126 break;
127 case '\'':
128 this.writer.write(APOS);
129 break;
130 case '\r':
131 this.writer.write(SLASH_R);
132 break;
133 default:
134 this.writer.write(c);
135 }
136 }
137 }
138
139 public void endNode() {
140 depth--;
141 if (tagIsEmpty) {
142 writer.write('/');
143 readyForNewLine = false;
144 finishTag();
145 elementStack.pop();
146 } else {
147 finishTag();
148 writer.write(CLOSE);
149 writer.write((String)elementStack.pop());
150 writer.write('>');
151 }
152 readyForNewLine = true;
153 if (depth == 0 ) {
154 writer.flush();
155 }
156 }
157
158 private void finishTag() {
159 if (tagInProgress) {
160 writer.write('>');
161 }
162 tagInProgress = false;
163 if (readyForNewLine) {
164 endOfLine();
165 }
166 readyForNewLine = false;
167 tagIsEmpty = false;
168 }
169
170 protected void endOfLine() {
171 writer.write(newLine);
172 for (int i = 0; i < depth; i++) {
173 writer.write(lineIndenter);
174 }
175 }
176
177 public void flush() {
178 writer.flush();
179 }
180
181 public void close() {
182 writer.close();
183 }
184 }