aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.bind.v2.runtime.output; aoqi@0: aoqi@0: import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler; aoqi@0: import java.io.IOException; aoqi@0: import java.io.OutputStream; aoqi@0: aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: aoqi@0: import com.sun.xml.internal.bind.v2.runtime.Name; aoqi@0: aoqi@0: import org.xml.sax.SAXException; aoqi@0: aoqi@0: /** aoqi@0: * {@link UTF8XmlOutput} with indentation. aoqi@0: * aoqi@0: * TODO: not sure if it's a good idea to move the indenting functionality to another class. aoqi@0: * aoqi@0: * Doesn't have to be final, but it helps the JVM. aoqi@0: * aoqi@0: * @author Kohsuke Kawaguchi aoqi@0: */ aoqi@0: public final class IndentingUTF8XmlOutput extends UTF8XmlOutput { aoqi@0: aoqi@0: /** aoqi@0: * Null if the writer should perform no indentation. aoqi@0: * aoqi@0: * Otherwise this will keep the 8 copies of the string for indentation. aoqi@0: * (so that we can write 8 indentation at once.) aoqi@0: */ aoqi@0: private final Encoded indent8; aoqi@0: aoqi@0: /** aoqi@0: * Length of one indentation. aoqi@0: */ aoqi@0: private final int unitLen; aoqi@0: aoqi@0: private int depth = 0; aoqi@0: aoqi@0: private boolean seenText = false; aoqi@0: aoqi@0: /** aoqi@0: * aoqi@0: * @param indentStr aoqi@0: * set to null for no indentation and optimal performance. aoqi@0: * otherwise the string is used for indentation. aoqi@0: */ aoqi@0: public IndentingUTF8XmlOutput(OutputStream out, String indentStr, Encoded[] localNames, CharacterEscapeHandler escapeHandler) { aoqi@0: super(out, localNames, escapeHandler); aoqi@0: aoqi@0: if(indentStr!=null) { aoqi@0: Encoded e = new Encoded(indentStr); aoqi@0: indent8 = new Encoded(); aoqi@0: indent8.ensureSize(e.len*8); aoqi@0: unitLen = e.len; aoqi@0: for( int i=0; i<8; i++ ) aoqi@0: System.arraycopy(e.buf, 0, indent8.buf, unitLen*i, unitLen); aoqi@0: } else { aoqi@0: this.indent8 = null; aoqi@0: this.unitLen = 0; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void beginStartTag(int prefix, String localName) throws IOException { aoqi@0: indentStartTag(); aoqi@0: super.beginStartTag(prefix, localName); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void beginStartTag(Name name) throws IOException { aoqi@0: indentStartTag(); aoqi@0: super.beginStartTag(name); aoqi@0: } aoqi@0: aoqi@0: private void indentStartTag() throws IOException { aoqi@0: closeStartTag(); aoqi@0: if(!seenText) aoqi@0: printIndent(); aoqi@0: depth++; aoqi@0: seenText = false; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void endTag(Name name) throws IOException { aoqi@0: indentEndTag(); aoqi@0: super.endTag(name); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void endTag(int prefix, String localName) throws IOException { aoqi@0: indentEndTag(); aoqi@0: super.endTag(prefix, localName); aoqi@0: } aoqi@0: aoqi@0: private void indentEndTag() throws IOException { aoqi@0: depth--; aoqi@0: if(!closeStartTagPending && !seenText) aoqi@0: printIndent(); aoqi@0: seenText = false; aoqi@0: } aoqi@0: aoqi@0: private void printIndent() throws IOException { aoqi@0: write('\n'); aoqi@0: int i = depth%8; aoqi@0: aoqi@0: write( indent8.buf, 0, i*unitLen ); aoqi@0: aoqi@0: i>>=3; // really i /= 8; aoqi@0: aoqi@0: for( ; i>0; i-- ) aoqi@0: indent8.write(this); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void text(String value, boolean needSP) throws IOException { aoqi@0: seenText = true; aoqi@0: super.text(value, needSP); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void text(Pcdata value, boolean needSP) throws IOException { aoqi@0: seenText = true; aoqi@0: super.text(value, needSP); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void endDocument(boolean fragment) throws IOException, SAXException, XMLStreamException { aoqi@0: write('\n'); aoqi@0: super.endDocument(fragment); aoqi@0: } aoqi@0: }