All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.w3c.tidy.PPrint Maven / Gradle / Ivy

There is a newer version: 1.2
Show newest version
/*
 * Copyright 2010 Alibaba Group Holding Limited.
 * All rights reserved.
 *
 * 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.
 */

/*
 * @(#)PPrint.java   1.11 2000/08/16
 *
 */

package org.w3c.tidy;

/**
 *
 * Pretty print parse tree
 *
 * (c) 1998-2000 (W3C) MIT, INRIA, Keio University
 * See Tidy.java for the copyright notice.
 * Derived from 
 * HTML Tidy Release 4 Aug 2000
 *
 * @author Dave Raggett 
 * @author Andy Quick  (translation to Java)
 * @version 1.0, 1999/05/22
 * @version 1.0.1, 1999/05/29
 * @version 1.1, 1999/06/18 Java Bean
 * @version 1.2, 1999/07/10 Tidy Release 7 Jul 1999
 * @version 1.3, 1999/07/30 Tidy Release 26 Jul 1999
 * @version 1.4, 1999/09/04 DOM support
 * @version 1.5, 1999/10/23 Tidy Release 27 Sep 1999
 * @version 1.6, 1999/11/01 Tidy Release 22 Oct 1999
 * @version 1.7, 1999/12/06 Tidy Release 30 Nov 1999
 * @version 1.8, 2000/01/22 Tidy Release 13 Jan 2000
 * @version 1.9, 2000/06/03 Tidy Release 30 Apr 2000
 * @version 1.10, 2000/07/22 Tidy Release 8 Jul 2000
 * @version 1.11, 2000/08/16 Tidy Release 4 Aug 2000
 */

/*
 Block-level and unknown elements are printed on
 new lines and their contents indented 2 spaces

 Inline elements are printed inline.

 Inline content is wrapped on spaces (except in
 attribute values or preformatted text, after
 start tags and before end tags
 */

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class PPrint {

    /* page transition effects */

    public static final short EFFECT_BLEND             = -1;
    public static final short EFFECT_BOX_IN            = 0;
    public static final short EFFECT_BOX_OUT           = 1;
    public static final short EFFECT_CIRCLE_IN         = 2;
    public static final short EFFECT_CIRCLE_OUT        = 3;
    public static final short EFFECT_WIPE_UP           = 4;
    public static final short EFFECT_WIPE_DOWN         = 5;
    public static final short EFFECT_WIPE_RIGHT        = 6;
    public static final short EFFECT_WIPE_LEFT         = 7;
    public static final short EFFECT_VERT_BLINDS       = 8;
    public static final short EFFECT_HORZ_BLINDS       = 9;
    public static final short EFFECT_CHK_ACROSS        = 10;
    public static final short EFFECT_CHK_DOWN          = 11;
    public static final short EFFECT_RND_DISSOLVE      = 12;
    public static final short EFFECT_SPLIT_VIRT_IN     = 13;
    public static final short EFFECT_SPLIT_VIRT_OUT    = 14;
    public static final short EFFECT_SPLIT_HORZ_IN     = 15;
    public static final short EFFECT_SPLIT_HORZ_OUT    = 16;
    public static final short EFFECT_STRIPS_LEFT_DOWN  = 17;
    public static final short EFFECT_STRIPS_LEFT_UP    = 18;
    public static final short EFFECT_STRIPS_RIGHT_DOWN = 19;
    public static final short EFFECT_STRIPS_RIGHT_UP   = 20;
    public static final short EFFECT_RND_BARS_HORZ     = 21;
    public static final short EFFECT_RND_BARS_VERT     = 22;
    public static final short EFFECT_RANDOM            = 23;

    private static final short NORMAL       = 0;
    private static final short PREFORMATTED = 1;
    private static final short COMMENT      = 2;
    private static final short ATTRIBVALUE  = 4;
    private static final short NOWRAP       = 8;
    private static final short CDATA        = 16;

    private int[]   linebuf  = null;
    private int     lbufsize = 0;
    private int     linelen  = 0;
    private int     wraphere = 0;
    private boolean inAttVal = false;
    private boolean InString = false;

    private int  slide        = 0;
    private int  count        = 0;
    private Node slidecontent = null;

    private Configuration configuration;

    public PPrint(Configuration configuration) {
        this.configuration = configuration;
    }

    /*
     * 1010 A 1011 B 1100 C 1101 D 1110 E 1111 F
     */

    /* return one less that the number of bytes used by UTF-8 char */
    /* str points to 1st byte,ch initialized to 1st byte */
    public static int getUTF8(byte[] str, int start, MutableInteger ch) {
        int c, n, i, bytes;

        c = str[start] & 0xFF; // Convert to unsigned.

        if ((c & 0xE0) == 0xC0) /* 110X XXXX two bytes */ {
            n = c & 31;
            bytes = 2;
        } else if ((c & 0xF0) == 0xE0) /* 1110 XXXX three bytes */ {
            n = c & 15;
            bytes = 3;
        } else if ((c & 0xF8) == 0xF0) /* 1111 0XXX four bytes */ {
            n = c & 7;
            bytes = 4;
        } else if ((c & 0xFC) == 0xF8) /* 1111 10XX five bytes */ {
            n = c & 3;
            bytes = 5;
        } else if ((c & 0xFE) == 0xFC) /* 1111 110X six bytes */

        {
            n = c & 1;
            bytes = 6;
        } else /* 0XXX XXXX one byte */ {
            ch.value = c;
            return 0;
        }

        /* successor bytes should have the form 10XX XXXX */
        for (i = 1; i < bytes; ++i) {
            c = str[start + i] & 0xFF; // Convert to unsigned.
            n = n << 6 | c & 0x3F;
        }

        ch.value = n;
        return bytes - 1;
    }

    /* store char c as UTF-8 encoded byte stream */
    public static int putUTF8(byte[] buf, int start, int c) {
        if (c < 128) {
            buf[start++] = (byte) c;
        } else if (c <= 0x7FF) {
            buf[start++] = (byte) (0xC0 | c >> 6);
            buf[start++] = (byte) (0x80 | c & 0x3F);
        } else if (c <= 0xFFFF) {
            buf[start++] = (byte) (0xE0 | c >> 12);
            buf[start++] = (byte) (0x80 | c >> 6 & 0x3F);
            buf[start++] = (byte) (0x80 | c & 0x3F);
        } else if (c <= 0x1FFFFF) {
            buf[start++] = (byte) (0xF0 | c >> 18);
            buf[start++] = (byte) (0x80 | c >> 12 & 0x3F);
            buf[start++] = (byte) (0x80 | c >> 6 & 0x3F);
            buf[start++] = (byte) (0x80 | c & 0x3F);
        } else {
            buf[start++] = (byte) (0xF8 | c >> 24);
            buf[start++] = (byte) (0x80 | c >> 18 & 0x3F);
            buf[start++] = (byte) (0x80 | c >> 12 & 0x3F);
            buf[start++] = (byte) (0x80 | c >> 6 & 0x3F);
            buf[start++] = (byte) (0x80 | c & 0x3F);
        }

        return start;
    }

    private void addC(int c, int index) {
        if (index + 1 >= lbufsize) {
            while (index + 1 >= lbufsize) {
                if (lbufsize == 0) {
                    lbufsize = 256;
                } else {
                    lbufsize = lbufsize * 2;
                }
            }

            int[] temp = new int[lbufsize];
            if (linebuf != null) {
                System.arraycopy(linebuf, 0, temp, 0, index);
            }
            linebuf = temp;
        }

        linebuf[index] = c;
    }

    private void wrapLine(Out fout, int indent) {
        int i, p, q;

        if (wraphere == 0) {
            return;
        }

        for (i = 0; i < indent; ++i) {
            fout.outc(' ');
        }

        for (i = 0; i < wraphere; ++i) {
            fout.outc(linebuf[i]);
        }

        if (InString) {
            fout.outc(' ');
            fout.outc('\\');
        }

        fout.newline();

        if (linelen > wraphere) {
            p = 0;

            if (linebuf[wraphere] == ' ') {
                ++wraphere;
            }

            q = wraphere;
            addC('\0', linelen);

            while (true) {
                linebuf[p] = linebuf[q];
                if (linebuf[q] == 0) {
                    break;
                }
                p++;
                q++;
            }
            linelen -= wraphere;
        } else {
            linelen = 0;
        }

        wraphere = 0;
    }

    private void wrapAttrVal(Out fout, int indent, boolean inString) {
        int i, p, q;

        for (i = 0; i < indent; ++i) {
            fout.outc(' ');
        }

        for (i = 0; i < wraphere; ++i) {
            fout.outc(linebuf[i]);
        }

        fout.outc(' ');

        if (inString) {
            fout.outc('\\');
        }

        fout.newline();

        if (linelen > wraphere) {
            p = 0;

            if (linebuf[wraphere] == ' ') {
                ++wraphere;
            }

            q = wraphere;
            addC('\0', linelen);

            while (true) {
                linebuf[p] = linebuf[q];
                if (linebuf[q] == 0) {
                    break;
                }
                p++;
                q++;
            }
            linelen -= wraphere;
        } else {
            linelen = 0;
        }

        wraphere = 0;
    }

    public void flushLine(Out fout, int indent) {
        int i;

        if (linelen > 0) {
            if (indent + linelen >= this.configuration.wraplen) {
                wrapLine(fout, indent);
            }

            if (!inAttVal || this.configuration.IndentAttributes) {
                for (i = 0; i < indent; ++i) {
                    fout.outc(' ');
                }
            }

            for (i = 0; i < linelen; ++i) {
                fout.outc(linebuf[i]);
            }
        }

        fout.newline();
        linelen = 0;
        wraphere = 0;
        inAttVal = false;
    }

    public void condFlushLine(Out fout, int indent) {
        int i;

        if (linelen > 0) {
            if (indent + linelen >= this.configuration.wraplen) {
                wrapLine(fout, indent);
            }

            if (!inAttVal || this.configuration.IndentAttributes) {
                for (i = 0; i < indent; ++i) {
                    fout.outc(' ');
                }
            }

            for (i = 0; i < linelen; ++i) {
                fout.outc(linebuf[i]);
            }

            fout.newline();
            linelen = 0;
            wraphere = 0;
            inAttVal = false;
        }
    }

    private void printChar(int c, short mode) {
        String entity;

        if (c == ' ' && !((mode & (PREFORMATTED | COMMENT | ATTRIBVALUE)) != 0)) {
            /* coerce a space character to a non-breaking space */
            if ((mode & NOWRAP) != 0) {
                /* by default XML doesn't define   */
                if (this.configuration.NumEntities || this.configuration.XmlTags) {
                    addC('&', linelen++);
                    addC('#', linelen++);
                    addC('1', linelen++);
                    addC('6', linelen++);
                    addC('0', linelen++);
                    addC(';', linelen++);
                } else /* otherwise use named entity */ {
                    addC('&', linelen++);
                    addC('n', linelen++);
                    addC('b', linelen++);
                    addC('s', linelen++);
                    addC('p', linelen++);
                    addC(';', linelen++);
                }
                return;
            } else {
                wraphere = linelen;
            }
        }

        /* comment characters are passed raw */
        if ((mode & COMMENT) != 0) {
            addC(c, linelen++);
            return;
        }

        /* except in CDATA map < to < etc. */
        if (!((mode & CDATA) != 0)) {
            if (c == '<') {
                addC('&', linelen++);
                addC('l', linelen++);
                addC('t', linelen++);
                addC(';', linelen++);
                return;
            }

            if (c == '>') {
                addC('&', linelen++);
                addC('g', linelen++);
                addC('t', linelen++);
                addC(';', linelen++);
                return;
            }

            /*
             * naked '&' chars can be left alone or quoted as & The latter
             * is required for XML where naked '&' are illegal.
             */
            if (c == '&' && this.configuration.QuoteAmpersand) {
                addC('&', linelen++);
                addC('a', linelen++);
                addC('m', linelen++);
                addC('p', linelen++);
                addC(';', linelen++);
                return;
            }

            if (c == '"' && this.configuration.QuoteMarks) {
                addC('&', linelen++);
                addC('q', linelen++);
                addC('u', linelen++);
                addC('o', linelen++);
                addC('t', linelen++);
                addC(';', linelen++);
                return;
            }

            if (c == '\'' && this.configuration.QuoteMarks) {
                addC('&', linelen++);
                addC('#', linelen++);
                addC('3', linelen++);
                addC('9', linelen++);
                addC(';', linelen++);
                return;
            }

            if (c == 160 && this.configuration.CharEncoding != Configuration.RAW) {
                if (this.configuration.QuoteNbsp) {
                    addC('&', linelen++);

                    if (this.configuration.NumEntities) {
                        addC('#', linelen++);
                        addC('1', linelen++);
                        addC('6', linelen++);
                        addC('0', linelen++);
                    } else {
                        addC('n', linelen++);
                        addC('b', linelen++);
                        addC('s', linelen++);
                        addC('p', linelen++);
                    }

                    addC(';', linelen++);
                } else {
                    addC(c, linelen++);
                }

                return;
            }
        }

        /* otherwise ISO 2022 characters are passed raw */
        if (this.configuration.CharEncoding == Configuration.ISO2022
            || this.configuration.CharEncoding == Configuration.RAW) {
            addC(c, linelen++);
            return;
        }

        /* if preformatted text, map   to space */
        if (c == 160 && (mode & PREFORMATTED) != 0) {
            addC(' ', linelen++);
            return;
        }

        /*
         * Filters from Word and PowerPoint often use smart quotes resulting in
         * character codes between 128 and 159. Unfortunately, the corresponding
         * HTML 4.0 entities for these are not widely supported. The following
         * converts dashes and quotation marks to the nearest ASCII equivalent.
         * My thanks to Andrzej Novosiolov for his help with this code.
         */

        if (this.configuration.MakeClean) {
            if (c >= 0x2013 && c <= 0x201E) {
                switch (c) {
                    case 0x2013:
                    case 0x2014:
                        c = '-';
                        break;
                    case 0x2018:
                    case 0x2019:
                    case 0x201A:
                        c = '\'';
                        break;
                    case 0x201C:
                    case 0x201D:
                    case 0x201E:
                        c = '"';
                        break;
                }
            }
        }

        /* don't map latin-1 chars to entities */
        if (this.configuration.CharEncoding == Configuration.LATIN1) {
            if (c > 255) /* multi byte chars */ {
                if (!this.configuration.NumEntities) {
                    entity = EntityTable.getDefaultEntityTable().entityName((short) c);
                    if (entity != null) {
                        entity = "&" + entity + ";";
                    } else {
                        entity = "&#" + c + ";";
                    }
                } else {
                    entity = "&#" + c + ";";
                }

                for (int i = 0; i < entity.length(); i++) {
                    addC(entity.charAt(i), linelen++);
                }

                return;
            }

            if (c > 126 && c < 160) {
                entity = "&#" + c + ";";

                for (int i = 0; i < entity.length(); i++) {
                    addC(entity.charAt(i), linelen++);
                }

                return;
            }

            addC(c, linelen++);
            return;
        }

        /* don't map utf8 chars to entities */
        if (this.configuration.CharEncoding == Configuration.UTF8) {
            addC(c, linelen++);
            return;
        }

        /* use numeric entities only for XML */
        if (this.configuration.XmlTags) {
            /* if ASCII use numeric entities for chars > 127 */
            if (c > 127 && this.configuration.CharEncoding == Configuration.ASCII) {
                entity = "&#" + c + ";";

                for (int i = 0; i < entity.length(); i++) {
                    addC(entity.charAt(i), linelen++);
                }

                return;
            }

            /* otherwise output char raw */
            addC(c, linelen++);
            return;
        }

        /* default treatment for ASCII */
        if (c > 126 || c < ' ' && c != '\t') {
            if (!this.configuration.NumEntities) {
                entity = EntityTable.getDefaultEntityTable().entityName((short) c);
                if (entity != null) {
                    entity = "&" + entity + ";";
                } else {
                    entity = "&#" + c + ";";
                }
            } else {
                entity = "&#" + c + ";";
            }

            for (int i = 0; i < entity.length(); i++) {
                addC(entity.charAt(i), linelen++);
            }

            return;
        }

        addC(c, linelen++);
    }

    /*
     * The line buffer is uint not char so we can hold Unicode values unencoded.
     * The translation to UTF-8 is deferred to the outc routine called to flush
     * the line buffer.
     */
    private void printText(Out fout, short mode, int indent, byte[] textarray, int start, int end) {
        int i, c;
        MutableInteger ci = new MutableInteger();

        for (i = start; i < end; ++i) {
            if (indent + linelen >= this.configuration.wraplen) {
                wrapLine(fout, indent);
            }

            c = textarray[i] & 0xFF; // Convert to unsigned.

            /* look for UTF-8 multibyte character */
            if (c > 0x7F) {
                i += getUTF8(textarray, i, ci);
                c = ci.value;
            }

            if (c == '\n') {
                flushLine(fout, indent);
                continue;
            }

            printChar(c, mode);
        }
    }

    private void printString(Out fout, int indent, String str) {
        for (int i = 0; i < str.length(); i++) {
            addC(str.charAt(i), linelen++);
        }
    }

    private void printAttrValue(Out fout, int indent, String value, int delim, boolean wrappable) {
        int c;
        MutableInteger ci = new MutableInteger();
        boolean wasinstring = false;
        byte[] valueChars = null;
        int i;
        short mode = wrappable ? (short) (NORMAL | ATTRIBVALUE) : (short) (PREFORMATTED | ATTRIBVALUE);

        if (value != null) {
            valueChars = Lexer.getBytes(value);
        }

        /* look for ASP, Tango or PHP instructions for computed attribute value */
        if (valueChars != null && valueChars.length >= 5 && valueChars[0] == '<') {
            if (valueChars[1] == '%' || valueChars[1] == '@' || new String(valueChars, 0, 5).equals("= this.configuration.wraplen) {
                wrapLine(fout, indent);
            }

            if (indent + linelen < this.configuration.wraplen) {
                wraphere = linelen;
            } else {
                condFlushLine(fout, indent);
            }
        }

        addC(delim, linelen++);

        if (value != null) {
            InString = false;

            i = 0;
            while (i < valueChars.length) {
                c = valueChars[i] & 0xFF; // Convert to unsigned.

                if (wrappable && c == ' ' && indent + linelen < this.configuration.wraplen) {
                    wraphere = linelen;
                    wasinstring = InString;
                }

                if (wrappable && wraphere > 0 && indent + linelen >= this.configuration.wraplen) {
                    wrapAttrVal(fout, indent, wasinstring);
                }

                if (c == delim) {
                    String entity;

                    entity = c == '"' ? """ : "'";

                    for (int j = 0; j < entity.length(); j++) {
                        addC(entity.charAt(j), linelen++);
                    }

                    ++i;
                    continue;
                } else if (c == '"') {
                    if (this.configuration.QuoteMarks) {
                        addC('&', linelen++);
                        addC('q', linelen++);
                        addC('u', linelen++);
                        addC('o', linelen++);
                        addC('t', linelen++);
                        addC(';', linelen++);
                    } else {
                        addC('"', linelen++);
                    }

                    if (delim == '\'') {
                        InString = !InString;
                    }

                    ++i;
                    continue;
                } else if (c == '\'') {
                    if (this.configuration.QuoteMarks) {
                        addC('&', linelen++);
                        addC('#', linelen++);
                        addC('3', linelen++);
                        addC('9', linelen++);
                        addC(';', linelen++);
                    } else {
                        addC('\'', linelen++);
                    }

                    if (delim == '"') {
                        InString = !InString;
                    }

                    ++i;
                    continue;
                }

                /* look for UTF-8 multibyte character */
                if (c > 0x7F) {
                    i += getUTF8(valueChars, i, ci);
                    c = ci.value;
                }

                ++i;

                if (c == '\n') {
                    flushLine(fout, indent);
                    continue;
                }

                printChar(c, mode);
            }
        }

        InString = false;
        addC(delim, linelen++);
    }

    private void printAttribute(Out fout, int indent, Node node, AttVal attr) {
        String name;
        boolean wrappable = false;

        if (this.configuration.IndentAttributes) {
            flushLine(fout, indent);
            indent += this.configuration.spaces;
        }

        name = attr.attribute;

        if (indent + linelen >= this.configuration.wraplen) {
            wrapLine(fout, indent);
        }

        if (!this.configuration.XmlTags && !this.configuration.XmlOut && attr.dict != null) {
            if (AttributeTable.getDefaultAttributeTable().isScript(name)) {
                wrappable = this.configuration.WrapScriptlets;
            } else if (!attr.dict.nowrap && this.configuration.WrapAttVals) {
                wrappable = true;
            }
        }

        if (indent + linelen < this.configuration.wraplen) {
            wraphere = linelen;
            addC(' ', linelen++);
        } else {
            condFlushLine(fout, indent);
            addC(' ', linelen++);
        }

        for (int i = 0; i < name.length(); i++) {
            addC(Lexer.foldCase(name.charAt(i), this.configuration.UpperCaseAttrs, this.configuration.XmlTags),
                 linelen++);
        }

        if (indent + linelen >= this.configuration.wraplen) {
            wrapLine(fout, indent);
        }

        if (attr.value == null) {
            if (this.configuration.XmlTags || this.configuration.XmlOut) {
                printAttrValue(fout, indent, attr.attribute, attr.delim, true);
            } else if (!attr.isBoolAttribute() && !Node.isNewNode(node)) {
                printAttrValue(fout, indent, "", attr.delim, true);
            } else if (indent + linelen < this.configuration.wraplen) {
                wraphere = linelen;
            }
        } else {
            printAttrValue(fout, indent, attr.value, attr.delim, wrappable);
        }
    }

    private void printAttrs(Out fout, int indent, Node node, AttVal attr) {
        if (attr != null) {
            if (attr.next != null) {
                printAttrs(fout, indent, node, attr.next);
            }

            if (attr.attribute != null) {
                printAttribute(fout, indent, node, attr);
            } else if (attr.asp != null) {
                addC(' ', linelen++);
                printAsp(fout, indent, attr.asp);
            } else if (attr.php != null) {
                addC(' ', linelen++);
                printPhp(fout, indent, attr.php);
            }
        }

        /* add xml:space attribute to pre and other elements */
        if (configuration.XmlOut && configuration.XmlSpace && ParserImpl.XMLPreserveWhiteSpace(node, configuration.tt)
            && node.getAttrByName("xml:space") == null) {
            printString(fout, indent, " xml:space=\"preserve\"");
        }
    }

    /*
     * Line can be wrapped immediately after inline start tag provided if
     * follows a text node ending in a space, or it parent is an inline element
     * that that rule applies to. This behaviour was reverse engineered from
     * Netscape 3.0
     */
    private static boolean afterSpace(Node node) {
        Node prev;
        int c;

        if (node == null || node.tag == null || !((node.tag.model & Dict.CM_INLINE) != 0)) {
            return true;
        }

        prev = node.prev;

        if (prev != null) {
            if (prev.type == Node.TextNode && prev.end > prev.start) {
                c = prev.textarray[prev.end - 1] & 0xFF; // Convert to unsigned.

                if (c == 160 || c == ' ' || c == '\n') {
                    return true;
                }
            }

            return false;
        }

        return afterSpace(node.parent);
    }

    private void printTag(Lexer lexer, Out fout, short mode, int indent, Node node) {
        char c;
        String p;
        TagTable tt = this.configuration.tt;

        addC('<', linelen++);

        if (node.type == Node.EndTag) {
            addC('/', linelen++);
        }

        p = node.element;
        for (int i = 0; i < p.length(); i++) {
            addC(Lexer.foldCase(p.charAt(i), this.configuration.UpperCaseTags, this.configuration.XmlTags), linelen++);
        }

        printAttrs(fout, indent, node, node.attributes);

        if ((this.configuration.XmlOut || lexer != null && lexer.isvoyager)
            && (node.type == Node.StartEndTag || (node.tag.model & Dict.CM_EMPTY) != 0)) {
            addC(' ', linelen++); /* compatibility hack */
            addC('/', linelen++);
        }

        addC('>', linelen++);
        ;

        if (node.type != Node.StartEndTag && !((mode & PREFORMATTED) != 0)) {
            if (indent + linelen >= this.configuration.wraplen) {
                wrapLine(fout, indent);
            }

            if (indent + linelen < this.configuration.wraplen) {
                /*
                 * wrap after start tag if is 
or if it's not inline or it * is an empty tag followed by */ if (afterSpace(node)) { if (!((mode & NOWRAP) != 0) && (!((node.tag.model & Dict.CM_INLINE) != 0) || node.tag == tt.tagBr || (node.tag.model & Dict.CM_EMPTY) != 0 && node.next == null && node.parent.tag == tt.tagA)) { wraphere = linelen; } } } else { condFlushLine(fout, indent); } } } private void printEndTag(Out fout, short mode, int indent, Node node) { char c; String p; /* * Netscape ignores SGML standard by not ignoring a line break before * or etc. To avoid rendering this as an underlined space, I * disable line wrapping before inline end tags by the #if 0 ... #endif */ if (false) { if (indent + linelen < this.configuration.wraplen && !((mode & NOWRAP) != 0)) { wraphere = linelen; } } addC('<', linelen++); addC('/', linelen++); p = node.element; for (int i = 0; i < p.length(); i++) { addC(Lexer.foldCase(p.charAt(i), this.configuration.UpperCaseTags, this.configuration.XmlTags), linelen++); } addC('>', linelen++); } private void printComment(Out fout, int indent, Node node) { if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } addC('<', linelen++); addC('!', linelen++); addC('-', linelen++); addC('-', linelen++); if (false) { if (linelen < this.configuration.wraplen) { wraphere = linelen; } } printText(fout, COMMENT, indent, node.textarray, node.start, node.end); if (false) { if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } } // See Lexer.java: AQ 8Jul2000 addC('-', linelen++); addC('-', linelen++); addC('>', linelen++); if (node.linebreak) { flushLine(fout, indent); } } private void printDocType(Out fout, int indent, Node node) { boolean q = this.configuration.QuoteMarks; this.configuration.QuoteMarks = false; if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } condFlushLine(fout, indent); addC('<', linelen++); addC('!', linelen++); addC('D', linelen++); addC('O', linelen++); addC('C', linelen++); addC('T', linelen++); addC('Y', linelen++); addC('P', linelen++); addC('E', linelen++); addC(' ', linelen++); if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } printText(fout, (short) 0, indent, node.textarray, node.start, node.end); if (linelen < this.configuration.wraplen) { wraphere = linelen; } addC('>', linelen++); this.configuration.QuoteMarks = q; condFlushLine(fout, indent); } private void printPI(Out fout, int indent, Node node) { if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } addC('<', linelen++); addC('?', linelen++); /* set CDATA to pass < and > unescaped */ printText(fout, CDATA, indent, node.textarray, node.start, node.end); if (node.textarray[node.end - 1] != (byte) '?') { addC('?', linelen++); } addC('>', linelen++); condFlushLine(fout, indent); } /* note ASP and JSTE share <% ... %> syntax */ private void printAsp(Out fout, int indent, Node node) { int savewraplen = this.configuration.wraplen; /* disable wrapping if so requested */ if (!this.configuration.WrapAsp || !this.configuration.WrapJste) { this.configuration.wraplen = 0xFFFFFF; /* a very large number */ } if (false) { //#if 0 if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } } //#endif addC('<', linelen++); addC('%', linelen++); printText(fout, this.configuration.WrapAsp ? CDATA : COMMENT, indent, node.textarray, node.start, node.end); addC('%', linelen++); addC('>', linelen++); /* condFlushLine(fout, indent); */ this.configuration.wraplen = savewraplen; } /* JSTE also supports <# ... #> syntax */ private void printJste(Out fout, int indent, Node node) { int savewraplen = this.configuration.wraplen; /* disable wrapping if so requested */ if (!this.configuration.WrapJste) { this.configuration.wraplen = 0xFFFFFF; /* a very large number */ } addC('<', linelen++); addC('#', linelen++); printText(fout, this.configuration.WrapJste ? CDATA : COMMENT, indent, node.textarray, node.start, node.end); addC('#', linelen++); addC('>', linelen++); /* condFlushLine(fout, indent); */ this.configuration.wraplen = savewraplen; } /* PHP is based on XML processing instructions */ private void printPhp(Out fout, int indent, Node node) { int savewraplen = this.configuration.wraplen; /* disable wrapping if so requested */ if (!this.configuration.WrapPhp) { this.configuration.wraplen = 0xFFFFFF; /* a very large number */ } if (false) { //#if 0 if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } } //#endif addC('<', linelen++); addC('?', linelen++); printText(fout, this.configuration.WrapPhp ? CDATA : COMMENT, indent, node.textarray, node.start, node.end); addC('?', linelen++); addC('>', linelen++); /* PCondFlushLine(fout, indent); */ this.configuration.wraplen = savewraplen; } private void printCDATA(Out fout, int indent, Node node) { int savewraplen = this.configuration.wraplen; condFlushLine(fout, indent); /* disable wrapping */ this.configuration.wraplen = 0xFFFFFF; /* a very large number */ addC('<', linelen++); addC('!', linelen++); addC('[', linelen++); addC('C', linelen++); addC('D', linelen++); addC('A', linelen++); addC('T', linelen++); addC('A', linelen++); addC('[', linelen++); printText(fout, COMMENT, indent, node.textarray, node.start, node.end); addC(']', linelen++); addC(']', linelen++); addC('>', linelen++); condFlushLine(fout, indent); this.configuration.wraplen = savewraplen; } private void printSection(Out fout, int indent, Node node) { int savewraplen = this.configuration.wraplen; /* disable wrapping if so requested */ if (!this.configuration.WrapSection) { this.configuration.wraplen = 0xFFFFFF; /* a very large number */ } if (false) { //#if 0 if (indent + linelen < this.configuration.wraplen) { wraphere = linelen; } } //#endif addC('<', linelen++); addC('!', linelen++); addC('[', linelen++); printText(fout, this.configuration.WrapSection ? CDATA : COMMENT, indent, node.textarray, node.start, node.end); addC(']', linelen++); addC('>', linelen++); /* PCondFlushLine(fout, indent); */ this.configuration.wraplen = savewraplen; } private boolean shouldIndent(Node node) { TagTable tt = this.configuration.tt; if (!this.configuration.IndentContent) { return false; } if (this.configuration.SmartIndent) { if (node.content != null && (node.tag.model & Dict.CM_NO_INDENT) != 0) { for (node = node.content; node != null; node = node.next) { if (node.tag != null && (node.tag.model & Dict.CM_BLOCK) != 0) { return true; } } return false; } if ((node.tag.model & Dict.CM_HEADING) != 0) { return false; } if (node.tag == tt.tagP) { return false; } if (node.tag == tt.tagTitle) { return false; } } if ((node.tag.model & (Dict.CM_FIELD | Dict.CM_OBJECT)) != 0) { return true; } if (node.tag == tt.tagMap) { return true; } return !((node.tag.model & Dict.CM_INLINE) != 0); } public void printTree(Out fout, short mode, int indent, Lexer lexer, Node node) { Node content, last; TagTable tt = this.configuration.tt; if (node == null) { return; } if (node.type == Node.TextNode) { printText(fout, mode, indent, node.textarray, node.start, node.end); } else if (node.type == Node.CommentTag) { printComment(fout, indent, node); } else if (node.type == Node.RootNode) { for (content = node.content; content != null; content = content.next) { printTree(fout, mode, indent, lexer, content); } } else if (node.type == Node.DocTypeTag) { printDocType(fout, indent, node); } else if (node.type == Node.ProcInsTag) { printPI(fout, indent, node); } else if (node.type == Node.CDATATag) { printCDATA(fout, indent, node); } else if (node.type == Node.SectionTag) { printSection(fout, indent, node); } else if (node.type == Node.AspTag) { printAsp(fout, indent, node); } else if (node.type == Node.JsteTag) { printJste(fout, indent, node); } else if (node.type == Node.PhpTag) { printPhp(fout, indent, node); } else if ((node.tag.model & Dict.CM_EMPTY) != 0 || node.type == Node.StartEndTag) { if (!((node.tag.model & Dict.CM_INLINE) != 0)) { condFlushLine(fout, indent); } if (node.tag == tt.tagBr && node.prev != null && node.prev.tag != tt.tagBr && this.configuration.BreakBeforeBR) { flushLine(fout, indent); } if (this.configuration.MakeClean && node.tag == tt.tagWbr) { printString(fout, indent, " "); } else { printTag(lexer, fout, mode, indent, node); } if (node.tag == tt.tagParam || node.tag == tt.tagArea) { condFlushLine(fout, indent); } else if (node.tag == tt.tagBr || node.tag == tt.tagHr) { flushLine(fout, indent); } } else /* some kind of container element */ { if (node.tag != null && node.tag.parser == ParserImpl.getParsePre()) { condFlushLine(fout, indent); indent = 0; condFlushLine(fout, indent); printTag(lexer, fout, mode, indent, node); flushLine(fout, indent); for (content = node.content; content != null; content = content.next) { printTree(fout, (short) (mode | PREFORMATTED | NOWRAP), indent, lexer, content); } condFlushLine(fout, indent); printEndTag(fout, mode, indent, node); flushLine(fout, indent); if (this.configuration.IndentContent == false && node.next != null) { flushLine(fout, indent); } } else if (node.tag == tt.tagStyle || node.tag == tt.tagScript) { condFlushLine(fout, indent); indent = 0; condFlushLine(fout, indent); printTag(lexer, fout, mode, indent, node); flushLine(fout, indent); for (content = node.content; content != null; content = content.next) { printTree(fout, (short) (mode | PREFORMATTED | NOWRAP | CDATA), indent, lexer, content); } condFlushLine(fout, indent); printEndTag(fout, mode, indent, node); flushLine(fout, indent); if (this.configuration.IndentContent == false && node.next != null) { flushLine(fout, indent); } } else if ((node.tag.model & Dict.CM_INLINE) != 0) { if (this.configuration.MakeClean) { /* discards and tags */ if (node.tag == tt.tagFont) { for (content = node.content; content != null; content = content.next) { printTree(fout, mode, indent, lexer, content); } return; } /* replace ... by   or   etc. */ if (node.tag == tt.tagNobr) { for (content = node.content; content != null; content = content.next) { printTree(fout, (short) (mode | NOWRAP), indent, lexer, content); } return; } } /* otherwise a normal inline element */ printTag(lexer, fout, mode, indent, node); /* indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET */ if (shouldIndent(node)) { condFlushLine(fout, indent); indent += this.configuration.spaces; for (content = node.content; content != null; content = content.next) { printTree(fout, mode, indent, lexer, content); } condFlushLine(fout, indent); indent -= this.configuration.spaces; condFlushLine(fout, indent); } else { for (content = node.content; content != null; content = content.next) { printTree(fout, mode, indent, lexer, content); } } printEndTag(fout, mode, indent, node); } else /* other tags */ { condFlushLine(fout, indent); if (this.configuration.SmartIndent && node.prev != null) { flushLine(fout, indent); } if (this.configuration.HideEndTags == false || !(node.tag != null && (node.tag.model & Dict.CM_OMITST) != 0)) { printTag(lexer, fout, mode, indent, node); if (shouldIndent(node)) { condFlushLine(fout, indent); } else if ((node.tag.model & Dict.CM_HTML) != 0 || node.tag == tt.tagNoframes || (node.tag.model & Dict.CM_HEAD) != 0 && !(node.tag == tt.tagTitle)) { flushLine(fout, indent); } } if (node.tag == tt.tagBody && this.configuration.BurstSlides) { printSlide(fout, mode, this.configuration.IndentContent ? indent + this.configuration.spaces : indent, lexer); } else { last = null; for (content = node.content; content != null; content = content.next) { /* kludge for naked text before block level tag */ if (last != null && !this.configuration.IndentContent && last.type == Node.TextNode && content.tag != null && (content.tag.model & Dict.CM_BLOCK) != 0) { flushLine(fout, indent); flushLine(fout, indent); } printTree(fout, mode, shouldIndent(node) ? indent + this.configuration.spaces : indent, lexer, content); last = content; } } /* don't flush line for td and th */ if (shouldIndent(node) || ((node.tag.model & Dict.CM_HTML) != 0 || node.tag == tt.tagNoframes || (node.tag.model & Dict.CM_HEAD) != 0 && !(node.tag == tt.tagTitle)) && this.configuration.HideEndTags == false) { condFlushLine(fout, this.configuration.IndentContent ? indent + this.configuration.spaces : indent); if (this.configuration.HideEndTags == false || !((node.tag.model & Dict.CM_OPT) != 0)) { printEndTag(fout, mode, indent, node); flushLine(fout, indent); } } else { if (this.configuration.HideEndTags == false || !((node.tag.model & Dict.CM_OPT) != 0)) { printEndTag(fout, mode, indent, node); } flushLine(fout, indent); } if (this.configuration.IndentContent == false && node.next != null && this.configuration.HideEndTags == false && (node.tag.model & (Dict.CM_BLOCK | Dict.CM_LIST | Dict.CM_DEFLIST | Dict.CM_TABLE)) != 0) { flushLine(fout, indent); } } } } public void printXMLTree(Out fout, short mode, int indent, Lexer lexer, Node node) { TagTable tt = this.configuration.tt; if (node == null) { return; } if (node.type == Node.TextNode) { printText(fout, mode, indent, node.textarray, node.start, node.end); } else if (node.type == Node.CommentTag) { condFlushLine(fout, indent); printComment(fout, 0, node); condFlushLine(fout, 0); } else if (node.type == Node.RootNode) { Node content; for (content = node.content; content != null; content = content.next) { printXMLTree(fout, mode, indent, lexer, content); } } else if (node.type == Node.DocTypeTag) { printDocType(fout, indent, node); } else if (node.type == Node.ProcInsTag) { printPI(fout, indent, node); } else if (node.type == Node.SectionTag) { printSection(fout, indent, node); } else if (node.type == Node.AspTag) { printAsp(fout, indent, node); } else if (node.type == Node.JsteTag) { printJste(fout, indent, node); } else if (node.type == Node.PhpTag) { printPhp(fout, indent, node); } else if ((node.tag.model & Dict.CM_EMPTY) != 0 || node.type == Node.StartEndTag) { condFlushLine(fout, indent); printTag(lexer, fout, mode, indent, node); flushLine(fout, indent); if (node.next != null) { flushLine(fout, indent); } } else /* some kind of container element */ { Node content; boolean mixed = false; int cindent; for (content = node.content; content != null; content = content.next) { if (content.type == Node.TextNode) { mixed = true; break; } } condFlushLine(fout, indent); if (ParserImpl.XMLPreserveWhiteSpace(node, tt)) { indent = 0; cindent = 0; mixed = false; } else if (mixed) { cindent = indent; } else { cindent = indent + this.configuration.spaces; } printTag(lexer, fout, mode, indent, node); if (!mixed) { flushLine(fout, indent); } for (content = node.content; content != null; content = content.next) { printXMLTree(fout, mode, cindent, lexer, content); } if (!mixed) { condFlushLine(fout, cindent); } printEndTag(fout, mode, indent, node); condFlushLine(fout, indent); if (node.next != null) { flushLine(fout, indent); } } } /* split parse tree by h2 elements and output to separate files */ /* counts number of h2 children belonging to node */ public int countSlides(Node node) { int n = 1; TagTable tt = this.configuration.tt; for (node = node.content; node != null; node = node.next) { if (node.tag == tt.tagH2) { ++n; } } return n; } /* * inserts a space gif called "dot.gif" to ensure that the slide is at least * n pixels high */ private void printVertSpacer(Out fout, int indent) { condFlushLine(fout, indent); printString(fout, indent, ""); condFlushLine(fout, indent); } private void printNavBar(Out fout, int indent) { String buf; condFlushLine(fout, indent); printString(fout, indent, "
"); if (slide > 1) { buf = "previous | "; printString(fout, indent, buf); condFlushLine(fout, indent); if (slide < count) { printString(fout, indent, "start | "); } else { printString(fout, indent, "start"); } condFlushLine(fout, indent); } if (slide < count) { buf = "next"; printString(fout, indent, buf); } printString(fout, indent, "
"); condFlushLine(fout, indent); } /* * Called from printTree to print the content of a slide from the node * slidecontent. On return slidecontent points to the node starting the next * slide or null. The variables slide and count are used to customise the * navigation bar. */ public void printSlide(Out fout, short mode, int indent, Lexer lexer) { Node content, last; TagTable tt = this.configuration.tt; /* insert div for onclick handler */ String s; s = "
"; printString(fout, indent, s); condFlushLine(fout, indent); /* first print the h2 element and navbar */ if (slidecontent.tag == tt.tagH2) { printNavBar(fout, indent); /* now print an hr after h2 */ addC('<', linelen++); addC(Lexer.foldCase('h', this.configuration.UpperCaseTags, this.configuration.XmlTags), linelen++); addC(Lexer.foldCase('r', this.configuration.UpperCaseTags, this.configuration.XmlTags), linelen++); if (this.configuration.XmlOut == true) { printString(fout, indent, " />"); } else { addC('>', linelen++); } if (this.configuration.IndentContent == true) { condFlushLine(fout, indent); } /* PrintVertSpacer(fout, indent); */ /* condFlushLine(fout, indent); */ /* print the h2 element */ printTree(fout, mode, this.configuration.IndentContent ? indent + this.configuration.spaces : indent, lexer, slidecontent); slidecontent = slidecontent.next; } /* now continue until we reach the next h2 */ last = null; content = slidecontent; for (; content != null; content = content.next) { if (content.tag == tt.tagH2) { break; } /* kludge for naked text before block level tag */ if (last != null && !this.configuration.IndentContent && last.type == Node.TextNode && content.tag != null && (content.tag.model & Dict.CM_BLOCK) != 0) { flushLine(fout, indent); flushLine(fout, indent); } printTree(fout, mode, this.configuration.IndentContent ? indent + this.configuration.spaces : indent, lexer, content); last = content; } slidecontent = content; /* now print epilog */ condFlushLine(fout, indent); printString(fout, indent, "
"); condFlushLine(fout, indent); addC('<', linelen++); addC(Lexer.foldCase('h', this.configuration.UpperCaseTags, this.configuration.XmlTags), linelen++); addC(Lexer.foldCase('r', this.configuration.UpperCaseTags, this.configuration.XmlTags), linelen++); if (this.configuration.XmlOut == true) { printString(fout, indent, " />"); } else { addC('>', linelen++); } if (this.configuration.IndentContent == true) { condFlushLine(fout, indent); } printNavBar(fout, indent); /* end tag for div */ printString(fout, indent, "
"); condFlushLine(fout, indent); } /* * Add meta element for page transition effect, this works on IE but not NS */ public void addTransitionEffect(Lexer lexer, Node root, short effect, double duration) { Node head = root.findHEAD(lexer.configuration.tt); String transition; if (0 <= effect && effect <= 23) { transition = "revealTrans(Duration=" + new Double(duration).toString() + ",Transition=" + effect + ")"; } else { transition = "blendTrans(Duration=" + new Double(duration).toString() + ")"; } if (head != null) { Node meta = lexer.inferredTag("meta"); meta.addAttribute("http-equiv", "Page-Enter"); meta.addAttribute("content", transition); Node.insertNodeAtStart(head, meta); } } public void createSlides(Lexer lexer, Node root) { Node body; String buf; Out out = new OutImpl(); body = root.findBody(lexer.configuration.tt); count = countSlides(body); slidecontent = body.content; addTransitionEffect(lexer, root, EFFECT_BLEND, 3.0); for (slide = 1; slide <= count; ++slide) { buf = "slide" + slide + ".html"; out.state = StreamIn.FSM_ASCII; out.encoding = this.configuration.CharEncoding; try { out.out = new FileOutputStream(buf); printTree(out, (short) 0, 0, lexer, root); flushLine(out, 0); out.out.close(); } catch (IOException e) { System.err.println(buf + e.toString()); } } /* * delete superfluous slides by deleting slideN.html for N = count+1, * count+2, etc. until no such file is found. */ for (; ; ) { buf = "slide" + slide + "html"; if (!new File(buf).delete()) { break; } ++slide; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy