Source Code Cross Referenced for PPrint.java in  » HTML-Parser » JTidy » org » w3c » tidy » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » HTML Parser » JTidy » org.w3c.tidy 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Java HTML Tidy - JTidy
0003:         *  HTML parser and pretty printer
0004:         *
0005:         *  Copyright (c) 1998-2000 World Wide Web Consortium (Massachusetts
0006:         *  Institute of Technology, Institut National de Recherche en
0007:         *  Informatique et en Automatique, Keio University). All Rights
0008:         *  Reserved.
0009:         *
0010:         *  Contributing Author(s):
0011:         *
0012:         *     Dave Raggett <dsr@w3.org>
0013:         *     Andy Quick <ac.quick@sympatico.ca> (translation to Java)
0014:         *     Gary L Peskin <garyp@firstech.com> (Java development)
0015:         *     Sami Lempinen <sami@lempinen.net> (release management)
0016:         *     Fabrizio Giustina <fgiust at users.sourceforge.net>
0017:         *
0018:         *  The contributing author(s) would like to thank all those who
0019:         *  helped with testing, bug fixes, and patience.  This wouldn't
0020:         *  have been possible without all of you.
0021:         *
0022:         *  COPYRIGHT NOTICE:
0023:         * 
0024:         *  This software and documentation is provided "as is," and
0025:         *  the copyright holders and contributing author(s) make no
0026:         *  representations or warranties, express or implied, including
0027:         *  but not limited to, warranties of merchantability or fitness
0028:         *  for any particular purpose or that the use of the software or
0029:         *  documentation will not infringe any third party patents,
0030:         *  copyrights, trademarks or other rights. 
0031:         *
0032:         *  The copyright holders and contributing author(s) will not be
0033:         *  liable for any direct, indirect, special or consequential damages
0034:         *  arising out of any use of the software or documentation, even if
0035:         *  advised of the possibility of such damage.
0036:         *
0037:         *  Permission is hereby granted to use, copy, modify, and distribute
0038:         *  this source code, or portions hereof, documentation and executables,
0039:         *  for any purpose, without fee, subject to the following restrictions:
0040:         *
0041:         *  1. The origin of this source code must not be misrepresented.
0042:         *  2. Altered versions must be plainly marked as such and must
0043:         *     not be misrepresented as being the original source.
0044:         *  3. This Copyright notice may not be removed or altered from any
0045:         *     source or altered source distribution.
0046:         * 
0047:         *  The copyright holders and contributing author(s) specifically
0048:         *  permit, without fee, and encourage the use of this source code
0049:         *  as a component for supporting the Hypertext Markup Language in
0050:         *  commercial products. If you use this source code in a product,
0051:         *  acknowledgment is not required but would be appreciated.
0052:         *
0053:         */
0054:        package org.w3c.tidy;
0055:
0056:        import java.io.File;
0057:        import java.io.FileOutputStream;
0058:        import java.io.IOException;
0059:        import java.text.NumberFormat;
0060:
0061:        /**
0062:         * Pretty print parse tree. Block-level and unknown elements are printed on new lines and their contents indented 2
0063:         * spaces Inline elements are printed inline. Inline content is wrapped on spaces (except in attribute values or
0064:         * preformatted text, after start tags and before end tags.
0065:         * @author Dave Raggett <a href="mailto:dsr@w3.org">dsr@w3.org </a>
0066:         * @author Andy Quick <a href="mailto:ac.quick@sympatico.ca">ac.quick@sympatico.ca </a> (translation to Java)
0067:         * @author Fabrizio Giustina
0068:         * @version $Revision: 1.60 $ ($Author: fgiust $)
0069:         */
0070:        public class PPrint {
0071:
0072:            /**
0073:             * position: normal.
0074:             */
0075:            private static final short NORMAL = 0;
0076:
0077:            /**
0078:             * position: preformatted text.
0079:             */
0080:            private static final short PREFORMATTED = 1;
0081:
0082:            /**
0083:             * position: comment.
0084:             */
0085:            private static final short COMMENT = 2;
0086:
0087:            /**
0088:             * position: attribute value.
0089:             */
0090:            private static final short ATTRIBVALUE = 4;
0091:
0092:            /**
0093:             * position: nowrap.
0094:             */
0095:            private static final short NOWRAP = 8;
0096:
0097:            /**
0098:             * position: cdata.
0099:             */
0100:            private static final short CDATA = 16;
0101:
0102:            /**
0103:             * Start cdata token.
0104:             */
0105:            private static final String CDATA_START = "<![CDATA[";
0106:
0107:            /**
0108:             * End cdata token.
0109:             */
0110:            private static final String CDATA_END = "]]>";
0111:
0112:            /**
0113:             * Javascript comment start.
0114:             */
0115:            private static final String JS_COMMENT_START = "//";
0116:
0117:            /**
0118:             * Javascript comment end.
0119:             */
0120:            private static final String JS_COMMENT_END = "";
0121:
0122:            /**
0123:             * VB comment start.
0124:             */
0125:            private static final String VB_COMMENT_START = "\'";
0126:
0127:            /**
0128:             * VB comment end.
0129:             */
0130:            private static final String VB_COMMENT_END = "";
0131:
0132:            /**
0133:             * CSS comment start.
0134:             */
0135:            private static final String CSS_COMMENT_START = "/*";
0136:
0137:            /**
0138:             * CSS comment end.
0139:             */
0140:            private static final String CSS_COMMENT_END = "*/";
0141:
0142:            /**
0143:             * Default comment start.
0144:             */
0145:            private static final String DEFAULT_COMMENT_START = "";
0146:
0147:            /**
0148:             * Default comment end.
0149:             */
0150:            private static final String DEFAULT_COMMENT_END = "";
0151:
0152:            private int[] linebuf;
0153:
0154:            private int lbufsize;
0155:
0156:            private int linelen;
0157:
0158:            private int wraphere;
0159:
0160:            private boolean inAttVal;
0161:
0162:            private boolean inString;
0163:
0164:            /**
0165:             * Current slide number.
0166:             */
0167:            private int slide;
0168:
0169:            /**
0170:             * Total slides count.
0171:             */
0172:            private int count;
0173:
0174:            private Node slidecontent;
0175:
0176:            /**
0177:             * current configuration.
0178:             */
0179:            private Configuration configuration;
0180:
0181:            /**
0182:             * Instantiates a new PPrint.
0183:             * @param configuration configuration
0184:             */
0185:            public PPrint(Configuration configuration) {
0186:                this .configuration = configuration;
0187:            }
0188:
0189:            /**
0190:             * @param ind
0191:             * @return
0192:             */
0193:            int cWrapLen(int ind) {
0194:                /* #431953 - start RJ Wraplen adjusted for smooth international ride */
0195:                if ("zh".equals(this .configuration.language)) {
0196:                    // Chinese characters take two positions on a fixed-width screen
0197:                    // It would be more accurate to keep a parallel linelen and wraphere incremented by 2 for Chinese characters
0198:                    // and 1 otherwise, but this is way simpler.
0199:                    return (ind + ((this .configuration.wraplen - ind) / 2));
0200:                }
0201:                if ("ja".equals(this .configuration.language)) {
0202:                    /* average Japanese text is 30% kanji */
0203:                    return (ind + (((this .configuration.wraplen - ind) * 7) / 10));
0204:                }
0205:                return (this .configuration.wraplen);
0206:                /* #431953 - end RJ */
0207:            }
0208:
0209:            /**
0210:             * return one less than the number of bytes used by the UTF-8 byte sequence. The Unicode char is returned in ch.
0211:             * @param str points to the UTF-8 byte sequence
0212:             * @param start starting offset in str
0213:             * @param ch initialized to 1st byte, passed as an array to allow modification
0214:             * @return one less that the number of bytes used by UTF-8 char
0215:             */
0216:            public static int getUTF8(byte[] str, int start, int[] ch) {
0217:
0218:                int[] n = new int[1];
0219:
0220:                int[] bytes = new int[] { 0 };
0221:
0222:                // first byte "str[0]" is passed in separately from the
0223:                // rest of the UTF-8 byte sequence starting at "str[1]"
0224:                byte[] successorBytes = str;
0225:
0226:                boolean err = EncodingUtils.decodeUTF8BytesToChar(n, TidyUtils
0227:                        .toUnsigned(str[start]), successorBytes, null, bytes,
0228:                        start + 1);
0229:
0230:                if (err) {
0231:                    n[0] = 0xFFFD; // replacement char
0232:                }
0233:                ch[0] = n[0];
0234:                return bytes[0] - 1;
0235:
0236:            }
0237:
0238:            /**
0239:             * store char c as UTF-8 encoded byte stream.
0240:             * @param buf
0241:             * @param start
0242:             * @param c
0243:             * @return
0244:             */
0245:            public static int putUTF8(byte[] buf, int start, int c) {
0246:                int[] count = new int[] { 0 };
0247:
0248:                boolean err = EncodingUtils.encodeCharToUTF8Bytes(c, buf, null,
0249:                        count);
0250:                if (err) {
0251:                    // replacement char 0xFFFD encoded as UTF-8
0252:                    buf[0] = (byte) 0xEF;
0253:                    buf[1] = (byte) 0xBF;
0254:                    buf[2] = (byte) 0xBD;
0255:                    count[0] = 3;
0256:                }
0257:
0258:                start += count[0];
0259:
0260:                return start;
0261:            }
0262:
0263:            private void addC(int c, int index) {
0264:                if (index + 1 >= lbufsize) {
0265:                    while (index + 1 >= lbufsize) {
0266:                        if (lbufsize == 0) {
0267:                            lbufsize = 256;
0268:                        } else {
0269:                            lbufsize = lbufsize * 2;
0270:                        }
0271:                    }
0272:
0273:                    int[] temp = new int[lbufsize];
0274:                    if (linebuf != null) {
0275:                        System.arraycopy(linebuf, 0, temp, 0, index);
0276:                    }
0277:                    linebuf = temp;
0278:                }
0279:
0280:                linebuf[index] = c;
0281:            }
0282:
0283:            /**
0284:             * Adds an ascii String.
0285:             * @param str String to be added
0286:             * @param index actual line lenght
0287:             * @return final line length
0288:             */
0289:            private int addAsciiString(String str, int index) {
0290:
0291:                int len = str.length();
0292:                if (index + len >= lbufsize) {
0293:                    while (index + len >= lbufsize) {
0294:                        if (lbufsize == 0) {
0295:                            lbufsize = 256;
0296:                        } else {
0297:                            lbufsize = lbufsize * 2;
0298:                        }
0299:                    }
0300:
0301:                    int[] temp = new int[lbufsize];
0302:                    if (linebuf != null) {
0303:                        System.arraycopy(linebuf, 0, temp, 0, index);
0304:                    }
0305:                    linebuf = temp;
0306:                }
0307:
0308:                for (int ix = 0; ix < len; ++ix) {
0309:                    linebuf[index + ix] = str.charAt(ix);
0310:                }
0311:                return index + len;
0312:            }
0313:
0314:            /**
0315:             * @param fout
0316:             * @param indent
0317:             */
0318:            private void wrapLine(Out fout, int indent) {
0319:                int i, p, q;
0320:
0321:                if (wraphere == 0) {
0322:                    return;
0323:                }
0324:
0325:                for (i = 0; i < indent; ++i) {
0326:                    fout.outc(' ');
0327:                }
0328:
0329:                for (i = 0; i < wraphere; ++i) {
0330:                    fout.outc(linebuf[i]);
0331:                }
0332:
0333:                if (inString) {
0334:                    fout.outc(' ');
0335:                    fout.outc('\\');
0336:                }
0337:
0338:                fout.newline();
0339:
0340:                if (linelen > wraphere) {
0341:                    p = 0;
0342:
0343:                    if (linebuf[wraphere] == ' ') {
0344:                        ++wraphere;
0345:                    }
0346:
0347:                    q = wraphere;
0348:                    addC('\0', linelen);
0349:
0350:                    while (true) {
0351:                        linebuf[p] = linebuf[q];
0352:                        if (linebuf[q] == 0) {
0353:                            break;
0354:                        }
0355:                        p++;
0356:                        q++;
0357:                    }
0358:                    linelen -= wraphere;
0359:                } else {
0360:                    linelen = 0;
0361:                }
0362:
0363:                wraphere = 0;
0364:            }
0365:
0366:            /**
0367:             * @param fout
0368:             * @param indent
0369:             * @param inString
0370:             */
0371:            private void wrapAttrVal(Out fout, int indent, boolean inString) {
0372:                int i, p, q;
0373:
0374:                for (i = 0; i < indent; ++i) {
0375:                    fout.outc(' ');
0376:                }
0377:
0378:                for (i = 0; i < wraphere; ++i) {
0379:                    fout.outc(linebuf[i]);
0380:                }
0381:
0382:                fout.outc(' ');
0383:
0384:                if (inString) {
0385:                    fout.outc('\\');
0386:                }
0387:
0388:                fout.newline();
0389:
0390:                if (linelen > wraphere) {
0391:                    p = 0;
0392:
0393:                    if (linebuf[wraphere] == ' ') {
0394:                        ++wraphere;
0395:                    }
0396:
0397:                    q = wraphere;
0398:                    addC('\0', linelen);
0399:
0400:                    while (true) {
0401:                        linebuf[p] = linebuf[q];
0402:                        if (linebuf[q] == 0) {
0403:                            break;
0404:                        }
0405:                        p++;
0406:                        q++;
0407:                    }
0408:                    linelen -= wraphere;
0409:                } else {
0410:                    linelen = 0;
0411:                }
0412:
0413:                wraphere = 0;
0414:            }
0415:
0416:            /**
0417:             * @param fout
0418:             * @param indent
0419:             */
0420:            public void flushLine(Out fout, int indent) {
0421:                int i;
0422:
0423:                if (linelen > 0) {
0424:                    if (indent + linelen >= this .configuration.wraplen) {
0425:                        wrapLine(fout, indent);
0426:                    }
0427:
0428:                    if (!inAttVal || this .configuration.indentAttributes) {
0429:                        for (i = 0; i < indent; ++i) {
0430:                            fout.outc(' ');
0431:                        }
0432:                    }
0433:
0434:                    for (i = 0; i < linelen; ++i) {
0435:                        fout.outc(linebuf[i]);
0436:                    }
0437:                }
0438:
0439:                fout.newline();
0440:                linelen = 0;
0441:                wraphere = 0;
0442:                inAttVal = false;
0443:            }
0444:
0445:            /**
0446:             * @param fout
0447:             * @param indent
0448:             */
0449:            public void condFlushLine(Out fout, int indent) {
0450:                int i;
0451:
0452:                if (linelen > 0) {
0453:                    if (indent + linelen >= this .configuration.wraplen) {
0454:                        wrapLine(fout, indent);
0455:                    }
0456:
0457:                    if (!inAttVal || this .configuration.indentAttributes) {
0458:                        for (i = 0; i < indent; ++i) {
0459:                            fout.outc(' ');
0460:                        }
0461:                    }
0462:
0463:                    for (i = 0; i < linelen; ++i) {
0464:                        fout.outc(linebuf[i]);
0465:                    }
0466:
0467:                    fout.newline();
0468:                    linelen = 0;
0469:                    wraphere = 0;
0470:                    inAttVal = false;
0471:                }
0472:            }
0473:
0474:            /**
0475:             * @param c
0476:             * @param mode
0477:             */
0478:            private void printChar(int c, short mode) {
0479:                String entity;
0480:                boolean breakable = false; // #431953 - RJ
0481:
0482:                if (c == ' '
0483:                        && !TidyUtils
0484:                                .toBoolean(mode
0485:                                        & (PREFORMATTED | COMMENT | ATTRIBVALUE | CDATA))) {
0486:                    // coerce a space character to a non-breaking space
0487:                    if (TidyUtils.toBoolean(mode & NOWRAP)) {
0488:                        // by default XML doesn't define &nbsp;
0489:                        if (this .configuration.numEntities
0490:                                || this .configuration.xmlTags) {
0491:                            addC('&', linelen++);
0492:                            addC('#', linelen++);
0493:                            addC('1', linelen++);
0494:                            addC('6', linelen++);
0495:                            addC('0', linelen++);
0496:                            addC(';', linelen++);
0497:                        } else {
0498:                            // otherwise use named entity
0499:                            addC('&', linelen++);
0500:                            addC('n', linelen++);
0501:                            addC('b', linelen++);
0502:                            addC('s', linelen++);
0503:                            addC('p', linelen++);
0504:                            addC(';', linelen++);
0505:                        }
0506:                        return;
0507:                    }
0508:                    wraphere = linelen;
0509:                }
0510:
0511:                // comment characters are passed raw
0512:                if (TidyUtils.toBoolean(mode & (COMMENT | CDATA))) {
0513:                    addC(c, linelen++);
0514:                    return;
0515:                }
0516:
0517:                // except in CDATA map < to &lt; etc.
0518:                if (!TidyUtils.toBoolean(mode & CDATA)) {
0519:                    if (c == '<') {
0520:                        addC('&', linelen++);
0521:                        addC('l', linelen++);
0522:                        addC('t', linelen++);
0523:                        addC(';', linelen++);
0524:                        return;
0525:                    }
0526:
0527:                    if (c == '>') {
0528:                        addC('&', linelen++);
0529:                        addC('g', linelen++);
0530:                        addC('t', linelen++);
0531:                        addC(';', linelen++);
0532:                        return;
0533:                    }
0534:
0535:                    // naked '&' chars can be left alone or quoted as &amp;
0536:                    // The latter is required for XML where naked '&' are illegal.
0537:                    if (c == '&' && this .configuration.quoteAmpersand) {
0538:                        addC('&', linelen++);
0539:                        addC('a', linelen++);
0540:                        addC('m', linelen++);
0541:                        addC('p', linelen++);
0542:                        addC(';', linelen++);
0543:                        return;
0544:                    }
0545:
0546:                    if (c == '"' && this .configuration.quoteMarks) {
0547:                        addC('&', linelen++);
0548:                        addC('q', linelen++);
0549:                        addC('u', linelen++);
0550:                        addC('o', linelen++);
0551:                        addC('t', linelen++);
0552:                        addC(';', linelen++);
0553:                        return;
0554:                    }
0555:
0556:                    if (c == '\'' && this .configuration.quoteMarks) {
0557:                        addC('&', linelen++);
0558:                        addC('#', linelen++);
0559:                        addC('3', linelen++);
0560:                        addC('9', linelen++);
0561:                        addC(';', linelen++);
0562:                        return;
0563:                    }
0564:
0565:                    if (c == 160 && !this .configuration.rawOut) {
0566:                        if (this .configuration.makeBare) {
0567:                            addC(' ', linelen++);
0568:                        } else if (this .configuration.quoteNbsp) {
0569:                            addC('&', linelen++);
0570:
0571:                            if (this .configuration.numEntities
0572:                                    || this .configuration.xmlTags) {
0573:                                addC('#', linelen++);
0574:                                addC('1', linelen++);
0575:                                addC('6', linelen++);
0576:                                addC('0', linelen++);
0577:                            } else {
0578:                                addC('n', linelen++);
0579:                                addC('b', linelen++);
0580:                                addC('s', linelen++);
0581:                                addC('p', linelen++);
0582:                            }
0583:
0584:                            addC(';', linelen++);
0585:                        } else {
0586:                            addC(c, linelen++);
0587:                        }
0588:
0589:                        return;
0590:                    }
0591:                }
0592:
0593:                // #431953 - start RJ
0594:                // Handle encoding-specific issues
0595:
0596:                switch (this .configuration.getOutCharEncoding()) {
0597:                case Configuration.UTF8:
0598:                    // Chinese doesn't have spaces, so it needs other kinds of breaks
0599:                    // This will also help documents using nice Unicode punctuation
0600:                    // But we leave the ASCII range punctuation untouched
0601:
0602:                    // Break after any punctuation or spaces characters
0603:                    if ((c >= 0x2000)
0604:                            && !TidyUtils.toBoolean(mode & PREFORMATTED)) {
0605:                        if (((c >= 0x2000) && (c <= 0x2006))
0606:                                || ((c >= 0x2008) && (c <= 0x2010))
0607:                                || ((c >= 0x2011) && (c <= 0x2046))
0608:                                || ((c >= 0x207D) && (c <= 0x207E))
0609:                                || ((c >= 0x208D) && (c <= 0x208E))
0610:                                || ((c >= 0x2329) && (c <= 0x232A))
0611:                                || ((c >= 0x3001) && (c <= 0x3003))
0612:                                || ((c >= 0x3008) && (c <= 0x3011))
0613:                                || ((c >= 0x3014) && (c <= 0x301F))
0614:                                || ((c >= 0xFD3E) && (c <= 0xFD3F))
0615:                                || ((c >= 0xFE30) && (c <= 0xFE44))
0616:                                || ((c >= 0xFE49) && (c <= 0xFE52))
0617:                                || ((c >= 0xFE54) && (c <= 0xFE61))
0618:                                || ((c >= 0xFE6A) && (c <= 0xFE6B))
0619:                                || ((c >= 0xFF01) && (c <= 0xFF03))
0620:                                || ((c >= 0xFF05) && (c <= 0xFF0A))
0621:                                || ((c >= 0xFF0C) && (c <= 0xFF0F))
0622:                                || ((c >= 0xFF1A) && (c <= 0xFF1B))
0623:                                || ((c >= 0xFF1F) && (c <= 0xFF20))
0624:                                || ((c >= 0xFF3B) && (c <= 0xFF3D))
0625:                                || ((c >= 0xFF61) && (c <= 0xFF65))) {
0626:                            wraphere = linelen + 2; // 2, because AddChar is not till later
0627:                            breakable = true;
0628:                        } else {
0629:                            switch (c) {
0630:                            case 0xFE63:
0631:                            case 0xFE68:
0632:                            case 0x3030:
0633:                            case 0x30FB:
0634:                            case 0xFF3F:
0635:                            case 0xFF5B:
0636:                            case 0xFF5D:
0637:                                wraphere = linelen + 2;
0638:                                breakable = true;
0639:                            }
0640:                        }
0641:                        // but break before a left punctuation
0642:                        if (breakable) {
0643:                            if (((c >= 0x201A) && (c <= 0x201C))
0644:                                    || ((c >= 0x201E) && (c <= 0x201F))) {
0645:                                wraphere--;
0646:                            } else {
0647:                                switch (c) {
0648:                                case 0x2018:
0649:                                case 0x2039:
0650:                                case 0x2045:
0651:                                case 0x207D:
0652:                                case 0x208D:
0653:                                case 0x2329:
0654:                                case 0x3008:
0655:                                case 0x300A:
0656:                                case 0x300C:
0657:                                case 0x300E:
0658:                                case 0x3010:
0659:                                case 0x3014:
0660:                                case 0x3016:
0661:                                case 0x3018:
0662:                                case 0x301A:
0663:                                case 0x301D:
0664:                                case 0xFD3E:
0665:                                case 0xFE35:
0666:                                case 0xFE37:
0667:                                case 0xFE39:
0668:                                case 0xFE3B:
0669:                                case 0xFE3D:
0670:                                case 0xFE3F:
0671:                                case 0xFE41:
0672:                                case 0xFE43:
0673:                                case 0xFE59:
0674:                                case 0xFE5B:
0675:                                case 0xFE5D:
0676:                                case 0xFF08:
0677:                                case 0xFF3B:
0678:                                case 0xFF5B:
0679:                                case 0xFF62:
0680:                                    wraphere--;
0681:                                }
0682:                            }
0683:                        }
0684:                    }
0685:                    break;
0686:                case Configuration.BIG5:
0687:                    // Allow linebreak at Chinese punctuation characters
0688:                    // There are not many spaces in Chinese
0689:                    addC(c, linelen++);
0690:                    if (((c & 0xFF00) == 0xA100)
0691:                            && !TidyUtils.toBoolean(mode & PREFORMATTED)) {
0692:                        wraphere = linelen;
0693:                        // opening brackets have odd codes: break before them
0694:                        if ((c > 0x5C) && (c < 0xAD) && ((c & 1) == 1)) {
0695:                            wraphere--;
0696:                        }
0697:                    }
0698:                    return;
0699:                case Configuration.SHIFTJIS:
0700:                case Configuration.ISO2022: // ISO 2022 characters are passed raw
0701:                    addC(c, linelen++);
0702:                    return;
0703:                default:
0704:                    if (this .configuration.rawOut) {
0705:                        addC(c, linelen++);
0706:                        return;
0707:                    }
0708:                    // #431953 - end RJ
0709:                }
0710:
0711:                // if preformatted text, map &nbsp; to space
0712:                if (c == 160 && TidyUtils.toBoolean(mode & PREFORMATTED)) {
0713:                    addC(' ', linelen++);
0714:                    return;
0715:                }
0716:
0717:                // Filters from Word and PowerPoint often use smart quotes resulting in character codes between 128 and 159.
0718:                // Unfortunately, the corresponding HTML 4.0 entities for these are not widely supported.
0719:                // The following converts dashes and quotation marks to the nearest ASCII equivalent.
0720:                // My thanks to Andrzej Novosiolov for his help with this code.
0721:
0722:                if (this .configuration.makeClean
0723:                        && this .configuration.asciiChars
0724:                        || this .configuration.makeBare) {
0725:                    if (c >= 0x2013 && c <= 0x201E) {
0726:                        switch (c) {
0727:                        case 0x2013: // en dash
0728:                        case 0x2014: // em dash
0729:                            c = '-';
0730:                            break;
0731:                        case 0x2018: // left single quotation mark
0732:                        case 0x2019: // right single quotation mark
0733:                        case 0x201A: // single low-9 quotation mark
0734:                            c = '\'';
0735:                            break;
0736:                        case 0x201C: // left double quotation mark
0737:                        case 0x201D: // right double quotation mark
0738:                        case 0x201E: // double low-9 quotation mark
0739:                            c = '"';
0740:                            break;
0741:                        }
0742:                    }
0743:                }
0744:
0745:                // don't map latin-1 chars to entities
0746:                if (this .configuration.getOutCharEncoding() == Configuration.LATIN1) {
0747:                    if (c > 255) /* multi byte chars */
0748:                    {
0749:                        if (!this .configuration.numEntities) {
0750:                            entity = EntityTable.getDefaultEntityTable()
0751:                                    .entityName((short) c);
0752:                            if (entity != null) {
0753:                                entity = "&" + entity + ";";
0754:                            } else {
0755:                                entity = "&#" + c + ";";
0756:                            }
0757:                        } else {
0758:                            entity = "&#" + c + ";";
0759:                        }
0760:
0761:                        for (int i = 0; i < entity.length(); i++) {
0762:                            addC(entity.charAt(i), linelen++);
0763:                        }
0764:
0765:                        return;
0766:                    }
0767:
0768:                    if (c > 126 && c < 160) {
0769:                        entity = "&#" + c + ";";
0770:
0771:                        for (int i = 0; i < entity.length(); i++) {
0772:                            addC(entity.charAt(i), linelen++);
0773:                        }
0774:
0775:                        return;
0776:                    }
0777:
0778:                    addC(c, linelen++);
0779:                    return;
0780:                }
0781:
0782:                // don't map utf8 or utf16 chars to entities
0783:                if (this .configuration.getOutCharEncoding() == Configuration.UTF8
0784:                        || this .configuration.getOutCharEncoding() == Configuration.UTF16
0785:                        || this .configuration.getOutCharEncoding() == Configuration.UTF16LE
0786:                        || this .configuration.getOutCharEncoding() == Configuration.UTF16BE) {
0787:                    addC(c, linelen++);
0788:                    return;
0789:                }
0790:
0791:                // use numeric entities only for XML
0792:                if (this .configuration.xmlTags) {
0793:                    // if ASCII use numeric entities for chars > 127
0794:                    if (c > 127
0795:                            && this .configuration.getOutCharEncoding() == Configuration.ASCII) {
0796:                        entity = "&#" + c + ";";
0797:
0798:                        for (int i = 0; i < entity.length(); i++) {
0799:                            addC(entity.charAt(i), linelen++);
0800:                        }
0801:
0802:                        return;
0803:                    }
0804:
0805:                    // otherwise output char raw
0806:                    addC(c, linelen++);
0807:                    return;
0808:                }
0809:
0810:                // default treatment for ASCII
0811:                if (this .configuration.getOutCharEncoding() == Configuration.ASCII
0812:                        && (c > 126 || (c < ' ' && c != '\t'))) {
0813:                    if (!this .configuration.numEntities) {
0814:                        entity = EntityTable.getDefaultEntityTable()
0815:                                .entityName((short) c);
0816:                        if (entity != null) {
0817:                            entity = "&" + entity + ";";
0818:                        } else {
0819:                            entity = "&#" + c + ";";
0820:                        }
0821:                    } else {
0822:                        entity = "&#" + c + ";";
0823:                    }
0824:
0825:                    for (int i = 0; i < entity.length(); i++) {
0826:                        addC(entity.charAt(i), linelen++);
0827:                    }
0828:
0829:                    return;
0830:                }
0831:
0832:                addC(c, linelen++);
0833:            }
0834:
0835:            /**
0836:             * The line buffer is uint not char so we can hold Unicode values unencoded. The translation to UTF-8 is deferred to
0837:             * the outc routine called to flush the line buffer.
0838:             * @param fout
0839:             * @param mode
0840:             * @param indent
0841:             * @param textarray
0842:             * @param start
0843:             * @param end
0844:             */
0845:            private void printText(Out fout, short mode, int indent,
0846:                    byte[] textarray, int start, int end) {
0847:                int i, c;
0848:                int[] ci = new int[1];
0849:
0850:                for (i = start; i < end; ++i) {
0851:                    if (indent + linelen >= this .configuration.wraplen) {
0852:                        wrapLine(fout, indent);
0853:                    }
0854:
0855:                    c = (textarray[i]) & 0xFF; // Convert to unsigned.
0856:
0857:                    // look for UTF-8 multibyte character
0858:                    if (c > 0x7F) {
0859:                        i += getUTF8(textarray, i, ci);
0860:                        c = ci[0];
0861:                    }
0862:
0863:                    if (c == '\n') {
0864:                        flushLine(fout, indent);
0865:                        continue;
0866:                    }
0867:
0868:                    printChar(c, mode);
0869:                }
0870:            }
0871:
0872:            /**
0873:             * @param str
0874:             */
0875:            private void printString(String str) {
0876:                for (int i = 0; i < str.length(); i++) {
0877:                    addC(str.charAt(i), linelen++);
0878:                }
0879:            }
0880:
0881:            /**
0882:             * @param fout
0883:             * @param indent
0884:             * @param value
0885:             * @param delim
0886:             * @param wrappable
0887:             */
0888:            private void printAttrValue(Out fout, int indent, String value,
0889:                    int delim, boolean wrappable) {
0890:                int c;
0891:                int[] ci = new int[1];
0892:                boolean wasinstring = false;
0893:                byte[] valueChars = null;
0894:                int i;
0895:                short mode = (wrappable ? (short) (NORMAL | ATTRIBVALUE)
0896:                        : (short) (PREFORMATTED | ATTRIBVALUE));
0897:
0898:                if (value != null) {
0899:                    valueChars = TidyUtils.getBytes(value);
0900:                }
0901:
0902:                // look for ASP, Tango or PHP instructions for computed attribute value
0903:                if (valueChars != null && valueChars.length >= 5
0904:                        && valueChars[0] == '<') {
0905:                    if (valueChars[1] == '%' || valueChars[1] == '@'
0906:                            || (new String(valueChars, 0, 5)).equals("<?php")) {
0907:                        mode |= CDATA;
0908:                    }
0909:                }
0910:
0911:                if (delim == 0) {
0912:                    delim = '"';
0913:                }
0914:
0915:                addC('=', linelen++);
0916:
0917:                // don't wrap after "=" for xml documents
0918:                if (!this .configuration.xmlOut) {
0919:
0920:                    if (indent + linelen < this .configuration.wraplen) {
0921:                        wraphere = linelen;
0922:                    }
0923:
0924:                    if (indent + linelen >= this .configuration.wraplen) {
0925:                        wrapLine(fout, indent);
0926:                    }
0927:
0928:                    if (indent + linelen < this .configuration.wraplen) {
0929:                        wraphere = linelen;
0930:                    } else {
0931:                        condFlushLine(fout, indent);
0932:                    }
0933:                }
0934:
0935:                addC(delim, linelen++);
0936:
0937:                if (value != null) {
0938:                    inString = false;
0939:
0940:                    i = 0;
0941:                    while (i < valueChars.length) {
0942:                        c = (valueChars[i]) & 0xFF; // Convert to unsigned.
0943:
0944:                        if (wrappable
0945:                                && c == ' '
0946:                                && indent + linelen < this .configuration.wraplen) {
0947:                            wraphere = linelen;
0948:                            wasinstring = inString;
0949:                        }
0950:
0951:                        if (wrappable
0952:                                && wraphere > 0
0953:                                && indent + linelen >= this .configuration.wraplen) {
0954:                            wrapAttrVal(fout, indent, wasinstring);
0955:                        }
0956:
0957:                        if (c == delim) {
0958:                            String entity;
0959:
0960:                            entity = (c == '"' ? "&quot;" : "&#39;");
0961:
0962:                            for (int j = 0; j < entity.length(); j++) {
0963:                                addC(entity.charAt(j), linelen++);
0964:                            }
0965:
0966:                            ++i;
0967:                            continue;
0968:                        } else if (c == '"') {
0969:                            if (this .configuration.quoteMarks) {
0970:                                addC('&', linelen++);
0971:                                addC('q', linelen++);
0972:                                addC('u', linelen++);
0973:                                addC('o', linelen++);
0974:                                addC('t', linelen++);
0975:                                addC(';', linelen++);
0976:                            } else {
0977:                                addC('"', linelen++);
0978:                            }
0979:
0980:                            if (delim == '\'') {
0981:                                inString = !inString;
0982:                            }
0983:
0984:                            ++i;
0985:                            continue;
0986:                        } else if (c == '\'') {
0987:                            if (this .configuration.quoteMarks) {
0988:                                addC('&', linelen++);
0989:                                addC('#', linelen++);
0990:                                addC('3', linelen++);
0991:                                addC('9', linelen++);
0992:                                addC(';', linelen++);
0993:                            } else {
0994:                                addC('\'', linelen++);
0995:                            }
0996:
0997:                            if (delim == '"') {
0998:                                inString = !inString;
0999:                            }
1000:
1001:                            ++i;
1002:                            continue;
1003:                        }
1004:
1005:                        // look for UTF-8 multibyte character
1006:                        if (c > 0x7F) {
1007:                            i += getUTF8(valueChars, i, ci);
1008:                            c = ci[0];
1009:                        }
1010:
1011:                        ++i;
1012:
1013:                        if (c == '\n') {
1014:                            flushLine(fout, indent);
1015:                            continue;
1016:                        }
1017:
1018:                        printChar(c, mode);
1019:                    }
1020:                }
1021:
1022:                inString = false;
1023:                addC(delim, linelen++);
1024:            }
1025:
1026:            /**
1027:             * @param fout
1028:             * @param indent
1029:             * @param node
1030:             * @param attr
1031:             */
1032:            private void printAttribute(Out fout, int indent, Node node,
1033:                    AttVal attr) {
1034:                String name;
1035:                boolean wrappable = false;
1036:
1037:                if (this .configuration.indentAttributes) {
1038:                    flushLine(fout, indent);
1039:                    indent += this .configuration.spaces;
1040:                }
1041:
1042:                name = attr.attribute;
1043:
1044:                if (indent + linelen >= this .configuration.wraplen) {
1045:                    wrapLine(fout, indent);
1046:                }
1047:
1048:                if (!this .configuration.xmlTags && !this .configuration.xmlOut
1049:                        && attr.dict != null) {
1050:                    if (AttributeTable.getDefaultAttributeTable()
1051:                            .isScript(name)) {
1052:                        wrappable = this .configuration.wrapScriptlets;
1053:                    } else if (!attr.dict.isNowrap()
1054:                            && this .configuration.wrapAttVals) {
1055:                        wrappable = true;
1056:                    }
1057:                }
1058:
1059:                if (indent + linelen < this .configuration.wraplen) {
1060:                    wraphere = linelen;
1061:                    addC(' ', linelen++);
1062:                } else {
1063:                    condFlushLine(fout, indent);
1064:                    addC(' ', linelen++);
1065:                }
1066:
1067:                for (int i = 0; i < name.length(); i++) {
1068:                    addC(TidyUtils.foldCase(name.charAt(i),
1069:                            this .configuration.upperCaseAttrs,
1070:                            this .configuration.xmlTags), linelen++);
1071:                }
1072:
1073:                if (indent + linelen >= this .configuration.wraplen) {
1074:                    wrapLine(fout, indent);
1075:                }
1076:
1077:                if (attr.value == null) {
1078:                    if (this .configuration.xmlTags || this .configuration.xmlOut) {
1079:                        printAttrValue(fout, indent,
1080:                                (attr.isBoolAttribute() ? attr.attribute : ""),
1081:                                attr.delim, true);
1082:                    } else if (!attr.isBoolAttribute() && node != null
1083:                            && !node.isNewNode()) {
1084:                        printAttrValue(fout, indent, "", attr.delim, true);
1085:                    } else if (indent + linelen < this .configuration.wraplen) {
1086:                        wraphere = linelen;
1087:                    }
1088:
1089:                } else {
1090:                    printAttrValue(fout, indent, attr.value, attr.delim,
1091:                            wrappable);
1092:                }
1093:            }
1094:
1095:            /**
1096:             * @param fout
1097:             * @param indent
1098:             * @param node
1099:             * @param attr
1100:             */
1101:            private void printAttrs(Out fout, int indent, Node node, AttVal attr) {
1102:                // add xml:space attribute to pre and other elements
1103:                if (configuration.xmlOut
1104:                        && configuration.xmlSpace
1105:                        && ParserImpl.XMLPreserveWhiteSpace(node,
1106:                                configuration.tt)
1107:                        && node.getAttrByName("xml:space") == null) {
1108:                    node.addAttribute("xml:space", "preserve");
1109:                    if (attr != null) {
1110:                        attr = node.attributes;
1111:                    }
1112:                }
1113:
1114:                if (attr != null) {
1115:                    if (attr.next != null) {
1116:                        printAttrs(fout, indent, node, attr.next);
1117:                    }
1118:
1119:                    if (attr.attribute != null) {
1120:                        Attribute attribute = attr.dict;
1121:
1122:                        if (!this .configuration.dropProprietaryAttributes
1123:                                || !(attribute == null || TidyUtils
1124:                                        .toBoolean(attribute.getVersions()
1125:                                                & Dict.VERS_PROPRIETARY))) {
1126:                            printAttribute(fout, indent, node, attr);
1127:                        }
1128:                    } else if (attr.asp != null) {
1129:                        addC(' ', linelen++);
1130:                        printAsp(fout, indent, attr.asp);
1131:                    } else if (attr.php != null) {
1132:                        addC(' ', linelen++);
1133:                        printPhp(fout, indent, attr.php);
1134:                    }
1135:                }
1136:
1137:            }
1138:
1139:            /**
1140:             * Line can be wrapped immediately after inline start tag provided if follows a text node ending in a space, or it
1141:             * parent is an inline element that that rule applies to. This behaviour was reverse engineered from Netscape 3.0
1142:             * @param node current Node
1143:             * @return <code>true</code> if the current char follows a space
1144:             */
1145:            private static boolean afterSpace(Node node) {
1146:                Node prev;
1147:                int c;
1148:
1149:                if (node == null
1150:                        || node.tag == null
1151:                        || !TidyUtils
1152:                                .toBoolean(node.tag.model & Dict.CM_INLINE)) {
1153:                    return true;
1154:                }
1155:
1156:                prev = node.prev;
1157:
1158:                if (prev != null) {
1159:                    if (prev.type == Node.TEXT_NODE && prev.end > prev.start) {
1160:                        c = (prev.textarray[prev.end - 1]) & 0xFF; // Convert to unsigned.
1161:
1162:                        if (c == 160 || c == ' ' || c == '\n') {
1163:                            return true;
1164:                        }
1165:                    }
1166:
1167:                    return false;
1168:                }
1169:
1170:                return afterSpace(node.parent);
1171:            }
1172:
1173:            /**
1174:             * @param lexer
1175:             * @param fout
1176:             * @param mode
1177:             * @param indent
1178:             * @param node
1179:             */
1180:            private void printTag(Lexer lexer, Out fout, short mode,
1181:                    int indent, Node node) {
1182:                String p;
1183:                TagTable tt = this .configuration.tt;
1184:
1185:                addC('<', linelen++);
1186:
1187:                if (node.type == Node.END_TAG) {
1188:                    addC('/', linelen++);
1189:                }
1190:
1191:                p = node.element;
1192:                for (int i = 0; i < p.length(); i++) {
1193:                    addC(TidyUtils.foldCase(p.charAt(i),
1194:                            this .configuration.upperCaseTags,
1195:                            this .configuration.xmlTags), linelen++);
1196:                }
1197:
1198:                printAttrs(fout, indent, node, node.attributes);
1199:
1200:                if ((this .configuration.xmlOut || this .configuration.xHTML)
1201:                        && (node.type == Node.START_END_TAG || TidyUtils
1202:                                .toBoolean(node.tag.model & Dict.CM_EMPTY))) {
1203:                    addC(' ', linelen++); // Space is NS compatibility hack <br />
1204:                    addC('/', linelen++); // Required end tag marker
1205:                }
1206:
1207:                addC('>', linelen++);
1208:
1209:                if ((node.type != Node.START_END_TAG || configuration.xHTML)
1210:                        && !TidyUtils.toBoolean(mode & PREFORMATTED)) {
1211:                    if (indent + linelen >= this .configuration.wraplen) {
1212:                        wrapLine(fout, indent);
1213:                    }
1214:
1215:                    if (indent + linelen < this .configuration.wraplen) {
1216:
1217:                        // wrap after start tag if is <br/> or if it's not inline
1218:                        // fix for [514348]
1219:                        if (!TidyUtils.toBoolean(mode & NOWRAP)
1220:                                && (!TidyUtils.toBoolean(node.tag.model
1221:                                        & Dict.CM_INLINE) || (node.tag == tt.tagBr))
1222:                                && afterSpace(node)) {
1223:                            wraphere = linelen;
1224:                        }
1225:
1226:                    }
1227:                } else {
1228:                    condFlushLine(fout, indent);
1229:                }
1230:
1231:            }
1232:
1233:            /**
1234:             * @param mode
1235:             * @param indent
1236:             * @param node
1237:             */
1238:            private void printEndTag(short mode, int indent, Node node) {
1239:                String p;
1240:
1241:                // Netscape ignores SGML standard by not ignoring a line break before </A> or </U> etc.
1242:                // To avoid rendering this as an underlined space, I disable line wrapping before inline end tags
1243:
1244:                // if (indent + linelen < this.configuration.wraplen && !TidyUtils.toBoolean(mode & NOWRAP))
1245:                // {
1246:                //     wraphere = linelen;
1247:                // }
1248:
1249:                addC('<', linelen++);
1250:                addC('/', linelen++);
1251:
1252:                p = node.element;
1253:                for (int i = 0; i < p.length(); i++) {
1254:                    addC(TidyUtils.foldCase(p.charAt(i),
1255:                            this .configuration.upperCaseTags,
1256:                            this .configuration.xmlTags), linelen++);
1257:                }
1258:
1259:                addC('>', linelen++);
1260:            }
1261:
1262:            /**
1263:             * @param fout
1264:             * @param indent
1265:             * @param node
1266:             */
1267:            private void printComment(Out fout, int indent, Node node) {
1268:                if (this .configuration.hideComments) {
1269:                    return;
1270:                }
1271:
1272:                if (indent + linelen < this .configuration.wraplen) {
1273:                    wraphere = linelen;
1274:                }
1275:
1276:                addC('<', linelen++);
1277:                addC('!', linelen++);
1278:                addC('-', linelen++);
1279:                addC('-', linelen++);
1280:
1281:                printText(fout, COMMENT, indent, node.textarray, node.start,
1282:                        node.end);
1283:
1284:                // See Lexer.java: AQ 8Jul2000
1285:                addC('-', linelen++);
1286:                addC('-', linelen++);
1287:                addC('>', linelen++);
1288:
1289:                if (node.linebreak) {
1290:                    flushLine(fout, indent);
1291:                }
1292:            }
1293:
1294:            /**
1295:             * @param fout
1296:             * @param indent
1297:             * @param lexer
1298:             * @param node
1299:             */
1300:            private void printDocType(Out fout, int indent, Lexer lexer,
1301:                    Node node) {
1302:                int i, c = 0;
1303:                short mode = 0;
1304:                boolean q = this .configuration.quoteMarks;
1305:
1306:                this .configuration.quoteMarks = false;
1307:
1308:                if (indent + linelen < this .configuration.wraplen) {
1309:                    wraphere = linelen;
1310:                }
1311:
1312:                condFlushLine(fout, indent);
1313:
1314:                addC('<', linelen++);
1315:                addC('!', linelen++);
1316:                addC('D', linelen++);
1317:                addC('O', linelen++);
1318:                addC('C', linelen++);
1319:                addC('T', linelen++);
1320:                addC('Y', linelen++);
1321:                addC('P', linelen++);
1322:                addC('E', linelen++);
1323:                addC(' ', linelen++);
1324:
1325:                if (indent + linelen < this .configuration.wraplen) {
1326:                    wraphere = linelen;
1327:                }
1328:
1329:                for (i = node.start; i < node.end; ++i) {
1330:                    if (indent + linelen >= this .configuration.wraplen) {
1331:                        wrapLine(fout, indent);
1332:                    }
1333:
1334:                    c = node.textarray[i] & 0xFF; // Convert to unsigned.
1335:
1336:                    // inDTDSubset?
1337:                    if (TidyUtils.toBoolean(mode & CDATA)) {
1338:                        if (c == ']') {
1339:                            mode &= ~CDATA;
1340:                        }
1341:                    } else if (c == '[') {
1342:                        mode |= CDATA;
1343:                    }
1344:                    int[] ci = new int[1];
1345:
1346:                    // look for UTF-8 multibyte character
1347:                    if (c > 0x7F) {
1348:                        i += getUTF8(node.textarray, i, ci);
1349:                        c = ci[0];
1350:                    }
1351:
1352:                    if (c == '\n') {
1353:                        flushLine(fout, indent);
1354:                        continue;
1355:                    }
1356:
1357:                    printChar(c, mode);
1358:                }
1359:
1360:                if (linelen < this .configuration.wraplen) {
1361:                    wraphere = linelen;
1362:                }
1363:
1364:                addC('>', linelen++);
1365:                this .configuration.quoteMarks = q;
1366:                condFlushLine(fout, indent);
1367:            }
1368:
1369:            /**
1370:             * @param fout
1371:             * @param indent
1372:             * @param node
1373:             */
1374:            private void printPI(Out fout, int indent, Node node) {
1375:                if (indent + linelen < this .configuration.wraplen) {
1376:                    wraphere = linelen;
1377:                }
1378:
1379:                addC('<', linelen++);
1380:                addC('?', linelen++);
1381:
1382:                // set CDATA to pass < and > unescaped
1383:                printText(fout, CDATA, indent, node.textarray, node.start,
1384:                        node.end);
1385:
1386:                if (node.end <= 0 || node.textarray[node.end - 1] != '?') // #542029 - fix by Terry Teague 10 Apr 02
1387:                {
1388:                    addC('?', linelen++);
1389:                }
1390:
1391:                addC('>', linelen++);
1392:                condFlushLine(fout, indent);
1393:            }
1394:
1395:            /**
1396:             * Pretty print the xml declaration.
1397:             * @param fout
1398:             * @param indent
1399:             * @param node
1400:             */
1401:            private void printXmlDecl(Out fout, int indent, Node node) {
1402:                if (indent + linelen < this .configuration.wraplen) {
1403:                    wraphere = linelen;
1404:                }
1405:
1406:                addC('<', linelen++);
1407:                addC('?', linelen++);
1408:                addC('x', linelen++);
1409:                addC('m', linelen++);
1410:                addC('l', linelen++);
1411:
1412:                printAttrs(fout, indent, node, node.attributes);
1413:
1414:                if (node.end <= 0 || node.textarray[node.end - 1] != '?') // #542029 - fix by Terry Teague 10 Apr 02
1415:                {
1416:                    addC('?', linelen++);
1417:                }
1418:
1419:                addC('>', linelen++);
1420:
1421:                condFlushLine(fout, indent);
1422:            }
1423:
1424:            /**
1425:             * note ASP and JSTE share <% ... %> syntax.
1426:             * @param fout
1427:             * @param indent
1428:             * @param node
1429:             */
1430:            private void printAsp(Out fout, int indent, Node node) {
1431:                int savewraplen = this .configuration.wraplen;
1432:
1433:                // disable wrapping if so requested
1434:
1435:                if (!this .configuration.wrapAsp || !this .configuration.wrapJste) {
1436:                    this .configuration.wraplen = 0xFFFFFF; // a very large number
1437:                }
1438:
1439:                addC('<', linelen++);
1440:                addC('%', linelen++);
1441:
1442:                printText(fout, (this .configuration.wrapAsp ? CDATA : COMMENT),
1443:                        indent, node.textarray, node.start, node.end);
1444:
1445:                addC('%', linelen++);
1446:                addC('>', linelen++);
1447:                /* condFlushLine(fout, indent); */
1448:                this .configuration.wraplen = savewraplen;
1449:            }
1450:
1451:            /**
1452:             * JSTE also supports <# ... #> syntax
1453:             * @param fout
1454:             * @param indent
1455:             * @param node
1456:             */
1457:            private void printJste(Out fout, int indent, Node node) {
1458:                int savewraplen = this .configuration.wraplen;
1459:
1460:                // disable wrapping if so requested
1461:
1462:                if (!this .configuration.wrapJste) {
1463:                    this .configuration.wraplen = 0xFFFFFF; // a very large number
1464:                }
1465:
1466:                addC('<', linelen++);
1467:                addC('#', linelen++);
1468:
1469:                printText(fout,
1470:                        (this .configuration.wrapJste ? CDATA : COMMENT),
1471:                        indent, node.textarray, node.start, node.end);
1472:
1473:                addC('#', linelen++);
1474:                addC('>', linelen++);
1475:                // condFlushLine(fout, indent);
1476:                this .configuration.wraplen = savewraplen;
1477:            }
1478:
1479:            /**
1480:             * PHP is based on XML processing instructions.
1481:             * @param fout
1482:             * @param indent
1483:             * @param node
1484:             */
1485:            private void printPhp(Out fout, int indent, Node node) {
1486:                int savewraplen = this .configuration.wraplen;
1487:
1488:                // disable wrapping if so requested
1489:
1490:                if (!this .configuration.wrapPhp) {
1491:                    this .configuration.wraplen = 0xFFFFFF; // a very large number
1492:                }
1493:
1494:                addC('<', linelen++);
1495:                addC('?', linelen++);
1496:
1497:                printText(fout, (this .configuration.wrapPhp ? CDATA : COMMENT),
1498:                        indent, node.textarray, node.start, node.end);
1499:
1500:                addC('?', linelen++);
1501:                addC('>', linelen++);
1502:                // PCondFlushLine(fout, indent);
1503:                this .configuration.wraplen = savewraplen;
1504:            }
1505:
1506:            /**
1507:             * @param fout
1508:             * @param indent
1509:             * @param node
1510:             */
1511:            private void printCDATA(Out fout, int indent, Node node) {
1512:                int savewraplen = this .configuration.wraplen;
1513:
1514:                if (!this .configuration.indentCdata) {
1515:                    indent = 0;
1516:                }
1517:
1518:                condFlushLine(fout, indent);
1519:
1520:                // disable wrapping
1521:                this .configuration.wraplen = 0xFFFFFF; // a very large number
1522:
1523:                addC('<', linelen++);
1524:                addC('!', linelen++);
1525:                addC('[', linelen++);
1526:                addC('C', linelen++);
1527:                addC('D', linelen++);
1528:                addC('A', linelen++);
1529:                addC('T', linelen++);
1530:                addC('A', linelen++);
1531:                addC('[', linelen++);
1532:
1533:                printText(fout, COMMENT, indent, node.textarray, node.start,
1534:                        node.end);
1535:
1536:                addC(']', linelen++);
1537:                addC(']', linelen++);
1538:                addC('>', linelen++);
1539:                condFlushLine(fout, indent);
1540:                this .configuration.wraplen = savewraplen;
1541:            }
1542:
1543:            /**
1544:             * @param fout
1545:             * @param indent
1546:             * @param node
1547:             */
1548:            private void printSection(Out fout, int indent, Node node) {
1549:                int savewraplen = this .configuration.wraplen;
1550:
1551:                // disable wrapping if so requested
1552:
1553:                if (!this .configuration.wrapSection) {
1554:                    this .configuration.wraplen = 0xFFFFFF; // a very large number
1555:                }
1556:
1557:                addC('<', linelen++);
1558:                addC('!', linelen++);
1559:                addC('[', linelen++);
1560:
1561:                printText(fout, (this .configuration.wrapSection ? CDATA
1562:                        : COMMENT), indent, node.textarray, node.start,
1563:                        node.end);
1564:
1565:                addC(']', linelen++);
1566:                addC('>', linelen++);
1567:                // PCondFlushLine(fout, indent);
1568:                this .configuration.wraplen = savewraplen;
1569:            }
1570:
1571:            /**
1572:             * Is the current node inside HEAD?
1573:             * @param node Node
1574:             * @return <code>true</code> if node is inside an HEAD tag
1575:             */
1576:            private boolean insideHead(Node node) {
1577:                if (node.tag == this .configuration.tt.tagHead) {
1578:                    return true;
1579:                }
1580:
1581:                if (node.parent != null) {
1582:                    return insideHead(node.parent);
1583:                }
1584:                return false;
1585:            }
1586:
1587:            /**
1588:             * Is text node and already ends w/ a newline? Used to pretty print CDATA/PRE text content. If it already ends on a
1589:             * newline, it is not necessary to print another before printing end tag.
1590:             * @param lexer Lexer
1591:             * @param node text node
1592:             * @return text indent
1593:             */
1594:            private int textEndsWithNewline(Lexer lexer, Node node) {
1595:                if (node.type == Node.TEXT_NODE && node.end > node.start) {
1596:                    int ch, ix = node.end - 1;
1597:                    // Skip non-newline whitespace
1598:                    while (ix >= node.start
1599:                            && TidyUtils
1600:                                    .toBoolean(ch = (node.textarray[ix] & 0xff))
1601:                            && (ch == ' ' || ch == '\t' || ch == '\r')) {
1602:                        --ix;
1603:                    }
1604:
1605:                    if (node.textarray[ix] == '\n') {
1606:                        return node.end - ix - 1; // #543262 tidy eats all memory
1607:                    }
1608:                }
1609:                return -1;
1610:            }
1611:
1612:            /**
1613:             * Does the current node contain a CDATA section?
1614:             * @param lexer Lexer
1615:             * @param node Node
1616:             * @return <code>true</code> if node contains a CDATA section
1617:             */
1618:            static boolean hasCDATA(Lexer lexer, Node node) {
1619:                // Scan forward through the textarray. Since the characters we're
1620:                // looking for are < 0x7f, we don't have to do any UTF-8 decoding.
1621:
1622:                if (node.type != Node.TEXT_NODE) {
1623:                    return false;
1624:                }
1625:
1626:                int len = node.end - node.start + 1;
1627:                String start = TidyUtils.getString(node.textarray, node.start,
1628:                        len);
1629:
1630:                int indexOfCData = start.indexOf(CDATA_START);
1631:                return indexOfCData > -1 && indexOfCData <= len;
1632:            }
1633:
1634:            /**
1635:             * Print script and style elements. For XHTML, wrap the content as follows:
1636:             * 
1637:             * <pre>
1638:             *     JavaScript:
1639:             *         //&lt;![CDATA[
1640:             *             content
1641:             *         //]]>
1642:             *     VBScript:
1643:             *         '&lt;![CDATA[
1644:             *             content
1645:             *         ']]>
1646:             *     CSS:
1647:             *         /*&lt;![CDATA[* /
1648:             *             content
1649:             *         /*]]>* /
1650:             *     other:
1651:             *        &lt;![CDATA[
1652:             *             content
1653:             *         ]]>
1654:             * </pre>
1655:             * 
1656:             * @param fout
1657:             * @param mode
1658:             * @param indent
1659:             * @param lexer
1660:             * @param node
1661:             */
1662:            private void printScriptStyle(Out fout, short mode, int indent,
1663:                    Lexer lexer, Node node) {
1664:                Node content;
1665:                String commentStart = DEFAULT_COMMENT_START;
1666:                String commentEnd = DEFAULT_COMMENT_END;
1667:                boolean hasCData = false;
1668:                int contentIndent = -1;
1669:
1670:                if (insideHead(node)) {
1671:                    // flushLine(fout, indent);
1672:                }
1673:
1674:                indent = 0;
1675:
1676:                // start script
1677:                printTag(lexer, fout, mode, indent, node);
1678:                // flushLine(fout, indent); // extra newline
1679:
1680:                if (lexer.configuration.xHTML && node.content != null) {
1681:                    AttVal type = node.getAttrByName("type");
1682:                    if (type != null) {
1683:                        if ("text/javascript".equalsIgnoreCase(type.value)) {
1684:                            commentStart = JS_COMMENT_START;
1685:                            commentEnd = JS_COMMENT_END;
1686:                        } else if ("text/css".equalsIgnoreCase(type.value)) {
1687:                            commentStart = CSS_COMMENT_START;
1688:                            commentEnd = CSS_COMMENT_END;
1689:                        } else if ("text/vbscript".equalsIgnoreCase(type.value)) {
1690:                            commentStart = VB_COMMENT_START;
1691:                            commentEnd = VB_COMMENT_END;
1692:                        }
1693:                    }
1694:
1695:                    hasCData = hasCDATA(lexer, node.content);
1696:                    if (!hasCData) {
1697:                        // disable wrapping
1698:                        int savewraplen = lexer.configuration.wraplen;
1699:                        lexer.configuration.wraplen = 0xFFFFFF; // a very large number
1700:
1701:                        linelen = addAsciiString(commentStart, linelen);
1702:                        linelen = addAsciiString(CDATA_START, linelen);
1703:                        linelen = addAsciiString(commentEnd, linelen);
1704:                        condFlushLine(fout, indent);
1705:
1706:                        // restore wrapping
1707:                        lexer.configuration.wraplen = savewraplen;
1708:                    }
1709:                }
1710:
1711:                for (content = node.content; content != null; content = content.next) {
1712:                    printTree(fout,
1713:                            (short) (mode | PREFORMATTED | NOWRAP | CDATA), 0,
1714:                            lexer, content);
1715:
1716:                    if (content.next == null) {
1717:                        contentIndent = textEndsWithNewline(lexer, content);
1718:                    }
1719:
1720:                }
1721:
1722:                if (contentIndent < 0) {
1723:                    condFlushLine(fout, indent);
1724:                    contentIndent = 0;
1725:                }
1726:
1727:                if (lexer.configuration.xHTML && node.content != null) {
1728:                    if (!hasCData) {
1729:                        // disable wrapping
1730:                        int ix, savewraplen = lexer.configuration.wraplen;
1731:                        lexer.configuration.wraplen = 0xFFFFFF; // a very large number
1732:
1733:                        // Add spaces to last text node to align w/ indent
1734:                        if (contentIndent > 0 && linelen < contentIndent) {
1735:                            linelen = contentIndent;
1736:                        }
1737:                        for (ix = 0; contentIndent < indent
1738:                                && ix < indent - contentIndent; ++ix) {
1739:                            addC(' ', linelen++);
1740:                        }
1741:
1742:                        linelen = addAsciiString(commentStart, linelen);
1743:                        linelen = addAsciiString(CDATA_END, linelen);
1744:                        linelen = addAsciiString(commentEnd, linelen);
1745:
1746:                        // restore wrapping
1747:                        lexer.configuration.wraplen = savewraplen;
1748:                        condFlushLine(fout, 0);
1749:                    }
1750:                }
1751:
1752:                printEndTag(mode, indent, node);
1753:
1754:                if (!lexer.configuration.indentContent
1755:                        && node.next != null
1756:
1757:                        && !((node.tag != null && TidyUtils
1758:                                .toBoolean(node.tag.model & Dict.CM_INLINE))
1759:
1760:                        || node.type != Node.TEXT_NODE
1761:
1762:                        )) {
1763:                    flushLine(fout, indent);
1764:                }
1765:
1766:                flushLine(fout, indent);
1767:            }
1768:
1769:            /**
1770:             * Should tidy indent the give tag?
1771:             * @param node actual node
1772:             * @return <code>true</code> if line should be indented
1773:             */
1774:            private boolean shouldIndent(Node node) {
1775:                TagTable tt = this .configuration.tt;
1776:
1777:                if (!this .configuration.indentContent) {
1778:                    return false;
1779:                }
1780:
1781:                if (this .configuration.smartIndent) {
1782:                    if (node.content != null
1783:                            && TidyUtils.toBoolean(node.tag.model
1784:                                    & Dict.CM_NO_INDENT)) {
1785:                        for (node = node.content; node != null; node = node.next) {
1786:                            if (node.tag != null
1787:                                    && TidyUtils.toBoolean(node.tag.model
1788:                                            & Dict.CM_BLOCK)) {
1789:                                return true;
1790:                            }
1791:                        }
1792:
1793:                        return false;
1794:                    }
1795:
1796:                    if (TidyUtils.toBoolean(node.tag.model & Dict.CM_HEADING)) {
1797:                        return false;
1798:                    }
1799:
1800:                    if (node.tag == tt.tagP) {
1801:                        return false;
1802:                    }
1803:
1804:                    if (node.tag == tt.tagTitle) {
1805:                        return false;
1806:                    }
1807:                }
1808:
1809:                if (TidyUtils.toBoolean(node.tag.model
1810:                        & (Dict.CM_FIELD | Dict.CM_OBJECT))) {
1811:                    return true;
1812:                }
1813:
1814:                if (node.tag == tt.tagMap) {
1815:                    return true;
1816:                }
1817:
1818:                return !TidyUtils.toBoolean(node.tag.model & Dict.CM_INLINE);
1819:            }
1820:
1821:            /**
1822:             * Print just the content of the body element. Useful when you want to reuse material from other documents.
1823:             * @param fout
1824:             * @param lexer
1825:             * @param root
1826:             * @param xml
1827:             */
1828:            void printBody(Out fout, Lexer lexer, Node root, boolean xml) {
1829:                if (root == null) {
1830:                    return;
1831:                }
1832:
1833:                // Feature request #434940 - fix by Dave Raggett/Ignacio Vazquez-Abrams 21 Jun 01
1834:                // Sebastiano Vigna <vigna@dsi.unimi.it>
1835:                Node body = root.findBody(lexer.configuration.tt);
1836:
1837:                if (body != null) {
1838:                    Node content;
1839:                    for (content = body.content; content != null; content = content.next) {
1840:                        if (xml) {
1841:                            printXMLTree(fout, (short) 0, 0, lexer, content);
1842:                        } else {
1843:                            printTree(fout, (short) 0, 0, lexer, content);
1844:                        }
1845:                    }
1846:                }
1847:            }
1848:
1849:            /**
1850:             * @param fout
1851:             * @param mode
1852:             * @param indent
1853:             * @param lexer
1854:             * @param node
1855:             */
1856:            public void printTree(Out fout, short mode, int indent,
1857:                    Lexer lexer, Node node) {
1858:                Node content, last;
1859:                TagTable tt = this .configuration.tt;
1860:
1861:                if (node == null) {
1862:                    return;
1863:                }
1864:
1865:                if (node.type == Node.TEXT_NODE
1866:                        || (node.type == Node.CDATA_TAG && lexer.configuration.escapeCdata)) {
1867:                    printText(fout, mode, indent, node.textarray, node.start,
1868:                            node.end);
1869:                } else if (node.type == Node.COMMENT_TAG) {
1870:                    printComment(fout, indent, node);
1871:                } else if (node.type == Node.ROOT_NODE) {
1872:                    for (content = node.content; content != null; content = content.next) {
1873:                        printTree(fout, mode, indent, lexer, content);
1874:                    }
1875:                } else if (node.type == Node.DOCTYPE_TAG) {
1876:                    printDocType(fout, indent, lexer, node);
1877:                } else if (node.type == Node.PROC_INS_TAG) {
1878:                    printPI(fout, indent, node);
1879:                } else if (node.type == Node.XML_DECL) {
1880:                    printXmlDecl(fout, indent, node);
1881:                } else if (node.type == Node.CDATA_TAG) {
1882:                    printCDATA(fout, indent, node);
1883:                } else if (node.type == Node.SECTION_TAG) {
1884:                    printSection(fout, indent, node);
1885:                } else if (node.type == Node.ASP_TAG) {
1886:                    printAsp(fout, indent, node);
1887:                } else if (node.type == Node.JSTE_TAG) {
1888:                    printJste(fout, indent, node);
1889:                } else if (node.type == Node.PHP_TAG) {
1890:                    printPhp(fout, indent, node);
1891:                } else if (TidyUtils.toBoolean(node.tag.model & Dict.CM_EMPTY)
1892:                        || (node.type == Node.START_END_TAG && !configuration.xHTML)) {
1893:                    if (!TidyUtils.toBoolean(node.tag.model & Dict.CM_INLINE)) {
1894:                        condFlushLine(fout, indent);
1895:                    }
1896:
1897:                    if (node.tag == tt.tagBr && node.prev != null
1898:                            && node.prev.tag != tt.tagBr
1899:                            && this .configuration.breakBeforeBR) {
1900:                        flushLine(fout, indent);
1901:                    }
1902:
1903:                    if (this .configuration.makeClean && node.tag == tt.tagWbr) {
1904:                        printString(" ");
1905:                    } else {
1906:                        printTag(lexer, fout, mode, indent, node);
1907:                    }
1908:
1909:                    if (node.tag == tt.tagParam || node.tag == tt.tagArea) {
1910:                        condFlushLine(fout, indent);
1911:                    } else if (node.tag == tt.tagBr || node.tag == tt.tagHr) {
1912:                        flushLine(fout, indent);
1913:                    }
1914:                } else {
1915:                    if (node.type == Node.START_END_TAG) {
1916:                        node.type = Node.START_TAG;
1917:                    }
1918:
1919:                    // some kind of container element
1920:                    if (node.tag != null
1921:                            && node.tag.getParser() == ParserImpl.PRE) {
1922:                        condFlushLine(fout, indent);
1923:
1924:                        indent = 0;
1925:                        condFlushLine(fout, indent);
1926:                        printTag(lexer, fout, mode, indent, node);
1927:                        flushLine(fout, indent);
1928:
1929:                        for (content = node.content; content != null; content = content.next) {
1930:                            printTree(fout,
1931:                                    (short) (mode | PREFORMATTED | NOWRAP),
1932:                                    indent, lexer, content);
1933:                        }
1934:
1935:                        condFlushLine(fout, indent);
1936:                        printEndTag(mode, indent, node);
1937:                        flushLine(fout, indent);
1938:
1939:                        if (!this .configuration.indentContent
1940:                                && node.next != null) {
1941:                            flushLine(fout, indent);
1942:                        }
1943:                    } else if (node.tag == tt.tagStyle
1944:                            || node.tag == tt.tagScript) {
1945:                        printScriptStyle(fout, (short) (mode | PREFORMATTED
1946:                                | NOWRAP | CDATA), indent, lexer, node);
1947:                    } else if (TidyUtils.toBoolean(node.tag.model
1948:                            & Dict.CM_INLINE)) {
1949:                        if (this .configuration.makeClean) {
1950:                            // discards <font> and </font> tags
1951:                            if (node.tag == tt.tagFont) {
1952:                                for (content = node.content; content != null; content = content.next) {
1953:                                    printTree(fout, mode, indent, lexer,
1954:                                            content);
1955:                                }
1956:                                return;
1957:                            }
1958:
1959:                            // replace <nobr> ... </nobr> by &nbsp; or &#160; etc.
1960:                            if (node.tag == tt.tagNobr) {
1961:                                for (content = node.content; content != null; content = content.next) {
1962:                                    printTree(fout, (short) (mode | NOWRAP),
1963:                                            indent, lexer, content);
1964:                                }
1965:                                return;
1966:                            }
1967:                        }
1968:
1969:                        // otherwise a normal inline element
1970:
1971:                        printTag(lexer, fout, mode, indent, node);
1972:
1973:                        // indent content for SELECT, TEXTAREA, MAP, OBJECT and APPLET
1974:
1975:                        if (shouldIndent(node)) {
1976:                            condFlushLine(fout, indent);
1977:                            indent += this .configuration.spaces;
1978:
1979:                            for (content = node.content; content != null; content = content.next) {
1980:                                printTree(fout, mode, indent, lexer, content);
1981:                            }
1982:
1983:                            condFlushLine(fout, indent);
1984:                            indent -= this .configuration.spaces;
1985:                            condFlushLine(fout, indent);
1986:                        } else {
1987:
1988:                            for (content = node.content; content != null; content = content.next) {
1989:                                printTree(fout, mode, indent, lexer, content);
1990:                            }
1991:                        }
1992:
1993:                        printEndTag(mode, indent, node);
1994:                    } else {
1995:                        // other tags
1996:                        condFlushLine(fout, indent);
1997:
1998:                        if (this .configuration.smartIndent && node.prev != null) {
1999:                            flushLine(fout, indent);
2000:                        }
2001:
2002:                        // do not omit elements with attributes
2003:                        if (!this .configuration.hideEndTags
2004:                                || !(node.tag != null && TidyUtils
2005:                                        .toBoolean(node.tag.model
2006:                                                & Dict.CM_OMITST))
2007:                                || node.attributes != null) {
2008:                            printTag(lexer, fout, mode, indent, node);
2009:
2010:                            if (shouldIndent(node)) {
2011:                                condFlushLine(fout, indent);
2012:                            } else if (TidyUtils.toBoolean(node.tag.model
2013:                                    & Dict.CM_HTML)
2014:                                    || node.tag == tt.tagNoframes
2015:                                    || (TidyUtils.toBoolean(node.tag.model
2016:                                            & Dict.CM_HEAD) && !(node.tag == tt.tagTitle))) {
2017:                                flushLine(fout, indent);
2018:                            }
2019:                        }
2020:
2021:                        if (node.tag == tt.tagBody
2022:                                && this .configuration.burstSlides) {
2023:                            printSlide(fout, mode,
2024:                                    (this .configuration.indentContent ? indent
2025:                                            + this .configuration.spaces
2026:                                            : indent), lexer);
2027:                        } else {
2028:                            last = null;
2029:
2030:                            for (content = node.content; content != null; content = content.next) {
2031:                                // kludge for naked text before block level tag
2032:                                if (last != null
2033:                                        && !this .configuration.indentContent
2034:                                        && last.type == Node.TEXT_NODE
2035:                                        && content.tag != null
2036:                                        && !TidyUtils
2037:                                                .toBoolean(content.tag.model
2038:                                                        & Dict.CM_INLINE)) {
2039:                                    flushLine(fout, indent);
2040:                                }
2041:
2042:                                printTree(fout, mode,
2043:                                        (shouldIndent(node) ? indent
2044:                                                + this .configuration.spaces
2045:                                                : indent), lexer, content);
2046:
2047:                                last = content;
2048:                            }
2049:                        }
2050:
2051:                        // don't flush line for td and th
2052:                        if (shouldIndent(node)
2053:                                || ((TidyUtils.toBoolean(node.tag.model
2054:                                        & Dict.CM_HTML)
2055:                                        || node.tag == tt.tagNoframes || //
2056:                                (TidyUtils.toBoolean(node.tag.model
2057:                                        & Dict.CM_HEAD) && !(node.tag == tt.tagTitle))) && //
2058:                                !this .configuration.hideEndTags)) {
2059:                            condFlushLine(fout,
2060:                                    (this .configuration.indentContent ? indent
2061:                                            + this .configuration.spaces
2062:                                            : indent));
2063:
2064:                            if (!this .configuration.hideEndTags
2065:                                    || !TidyUtils.toBoolean(node.tag.model
2066:                                            & Dict.CM_OPT)) {
2067:                                printEndTag(mode, indent, node);
2068:
2069:                                // #603128 tidy adds newslines after </html> tag
2070:                                // Fix by Fabrizio Giustina 12-02-2004
2071:                                // fix is different from the one in original tidy
2072:                                if (!lexer.seenEndHtml) {
2073:                                    flushLine(fout, indent);
2074:                                }
2075:                            }
2076:                        } else {
2077:                            if (!this .configuration.hideEndTags
2078:                                    || !TidyUtils.toBoolean(node.tag.model
2079:                                            & Dict.CM_OPT)) {
2080:                                printEndTag(mode, indent, node);
2081:                            }
2082:
2083:                            flushLine(fout, indent);
2084:                        }
2085:
2086:                        // FG commented out: double newlines
2087:                        // if (!this.configuration.indentContent
2088:                        //     && node.next != null
2089:                        //     && !this.configuration.hideEndTags
2090:                        //     && (node.tag.model
2091:                        //     & TidyUtils.toBoolean(Dict.CM_BLOCK | Dict.CM_TABLE | Dict.CM_LIST | Dict.CM_DEFLIST)))
2092:                        //     {
2093:                        //         flushLine(fout, indent);
2094:                        //     }
2095:                    }
2096:                }
2097:            }
2098:
2099:            /**
2100:             * @param fout
2101:             * @param mode
2102:             * @param indent
2103:             * @param lexer
2104:             * @param node
2105:             */
2106:            public void printXMLTree(Out fout, short mode, int indent,
2107:                    Lexer lexer, Node node) {
2108:                TagTable tt = this .configuration.tt;
2109:
2110:                if (node == null) {
2111:                    return;
2112:                }
2113:
2114:                if (node.type == Node.TEXT_NODE
2115:                        || (node.type == Node.CDATA_TAG && lexer.configuration.escapeCdata)) {
2116:                    printText(fout, mode, indent, node.textarray, node.start,
2117:                            node.end);
2118:                } else if (node.type == Node.COMMENT_TAG) {
2119:                    condFlushLine(fout, indent);
2120:                    printComment(fout, 0, node);
2121:                    condFlushLine(fout, 0);
2122:                } else if (node.type == Node.ROOT_NODE) {
2123:                    Node content;
2124:
2125:                    for (content = node.content; content != null; content = content.next) {
2126:                        printXMLTree(fout, mode, indent, lexer, content);
2127:                    }
2128:                } else if (node.type == Node.DOCTYPE_TAG) {
2129:                    printDocType(fout, indent, lexer, node);
2130:                } else if (node.type == Node.PROC_INS_TAG) {
2131:                    printPI(fout, indent, node);
2132:                } else if (node.type == Node.XML_DECL) {
2133:                    printXmlDecl(fout, indent, node);
2134:                } else if (node.type == Node.CDATA_TAG) {
2135:                    printCDATA(fout, indent, node);
2136:                } else if (node.type == Node.SECTION_TAG) {
2137:                    printSection(fout, indent, node);
2138:                } else if (node.type == Node.ASP_TAG) {
2139:                    printAsp(fout, indent, node);
2140:                } else if (node.type == Node.JSTE_TAG) {
2141:                    printJste(fout, indent, node);
2142:                } else if (node.type == Node.PHP_TAG) {
2143:                    printPhp(fout, indent, node);
2144:                } else if (TidyUtils.toBoolean(node.tag.model & Dict.CM_EMPTY)
2145:                        || node.type == Node.START_END_TAG
2146:                        && !configuration.xHTML) {
2147:                    condFlushLine(fout, indent);
2148:                    printTag(lexer, fout, mode, indent, node);
2149:                    // fgiust: Remove empty lines between tags in XML.
2150:                    //flushLine(fout, indent);
2151:
2152:                    // CPR: folks don't want so much vertical spacing in XML
2153:                    // if (node.next != null) { flushLine(fout, indent); }
2154:
2155:                } else {
2156:                    // some kind of container element
2157:                    Node content;
2158:                    boolean mixed = false;
2159:                    int cindent;
2160:
2161:                    for (content = node.content; content != null; content = content.next) {
2162:                        if (content.type == Node.TEXT_NODE) {
2163:                            mixed = true;
2164:                            break;
2165:                        }
2166:                    }
2167:
2168:                    condFlushLine(fout, indent);
2169:
2170:                    if (ParserImpl.XMLPreserveWhiteSpace(node, tt)) {
2171:                        indent = 0;
2172:                        cindent = 0;
2173:                        mixed = false;
2174:                    } else if (mixed) {
2175:                        cindent = indent;
2176:                    } else {
2177:                        cindent = indent + this .configuration.spaces;
2178:                    }
2179:
2180:                    printTag(lexer, fout, mode, indent, node);
2181:
2182:                    if (!mixed && node.content != null) {
2183:                        flushLine(fout, indent);
2184:                    }
2185:
2186:                    for (content = node.content; content != null; content = content.next) {
2187:                        printXMLTree(fout, mode, cindent, lexer, content);
2188:                    }
2189:
2190:                    if (!mixed && node.content != null) {
2191:                        condFlushLine(fout, cindent);
2192:                    }
2193:                    printEndTag(mode, indent, node);
2194:                    //condFlushLine(fout, indent);
2195:
2196:                    // CPR: folks don't want so much vertical spacing in XML
2197:                    // if (node.next != null) { flushLine(fout, indent); }
2198:
2199:                }
2200:            }
2201:
2202:            /**
2203:             * Split parse tree by h2 elements and output to separate files. Counts number of h2 children (if any) belonging to
2204:             * node.
2205:             * @param node root node
2206:             * @return number of slides (number of h2 elements)
2207:             */
2208:            public int countSlides(Node node) {
2209:                // assume minimum of 1 slide
2210:                int n = 1;
2211:
2212:                TagTable tt = this .configuration.tt;
2213:
2214:                //fix for [431716] avoid empty slides
2215:                if (node != null && node.content != null
2216:                        && node.content.tag == tt.tagH2) {
2217:                    // "first" slide is empty, so ignore it
2218:                    n--;
2219:                }
2220:
2221:                if (node != null) {
2222:                    for (node = node.content; node != null; node = node.next) {
2223:                        if (node.tag == tt.tagH2) {
2224:                            ++n;
2225:                        }
2226:                    }
2227:                }
2228:
2229:                return n;
2230:            }
2231:
2232:            /**
2233:             * @param fout
2234:             * @param indent
2235:             */
2236:            private void printNavBar(Out fout, int indent) {
2237:                String buf;
2238:
2239:                condFlushLine(fout, indent);
2240:                printString("<center><small>");
2241:
2242:                NumberFormat numberFormat = NumberFormat.getInstance();
2243:                numberFormat.setMinimumIntegerDigits(3);
2244:
2245:                if (slide > 1) {
2246:                    buf = "<a href=\"slide" + numberFormat.format(slide - 1)
2247:                            + ".html\">previous</a> | ";
2248:                    // #427666 - fix by Eric Rossen 02 Aug 00
2249:                    printString(buf);
2250:                    condFlushLine(fout, indent);
2251:
2252:                    if (slide < count) {
2253:                        printString("<a href=\"slide001.html\">start</a> | ");
2254:                        // #427666 - fix by Eric Rossen 02 Aug 00
2255:                    } else {
2256:                        printString("<a href=\"slide001.html\">start</a>");
2257:                        // #427666 - fix by Eric Rossen 02 Aug 00
2258:                    }
2259:
2260:                    condFlushLine(fout, indent);
2261:                }
2262:
2263:                if (slide < count) {
2264:                    buf = "<a href=\"slide" + numberFormat.format(slide + 1)
2265:                            + ".html\">next</a>";
2266:                    // #427666 - fix by Eric Rossen 02 Aug 00
2267:                    printString(buf);
2268:                }
2269:
2270:                printString("</small></center>");
2271:                condFlushLine(fout, indent);
2272:            }
2273:
2274:            /**
2275:             * Called from printTree to print the content of a slide from the node slidecontent. On return slidecontent points
2276:             * to the node starting the next slide or null. The variables slide and count are used to customise the navigation
2277:             * bar.
2278:             * @param fout
2279:             * @param mode
2280:             * @param indent
2281:             * @param lexer
2282:             */
2283:            public void printSlide(Out fout, short mode, int indent, Lexer lexer) {
2284:                Node content, last;
2285:                TagTable tt = this .configuration.tt;
2286:
2287:                NumberFormat numberFormat = NumberFormat.getInstance();
2288:                numberFormat.setMinimumIntegerDigits(3);
2289:
2290:                /* insert div for onclick handler */
2291:                String s;
2292:                s = "<div onclick=\"document.location='slide"
2293:                        + numberFormat.format(slide < count ? slide + 1 : 1)
2294:                        + ".html'\">";
2295:                // #427666 - fix by Eric Rossen 02 Aug 00
2296:                printString(s);
2297:                condFlushLine(fout, indent);
2298:
2299:                /* first print the h2 element and navbar */
2300:                if (slidecontent != null && slidecontent.tag == tt.tagH2) {
2301:                    printNavBar(fout, indent);
2302:
2303:                    /* now print an hr after h2 */
2304:
2305:                    addC('<', linelen++);
2306:
2307:                    addC(TidyUtils.foldCase('h',
2308:                            this .configuration.upperCaseTags,
2309:                            this .configuration.xmlTags), linelen++);
2310:                    addC(TidyUtils.foldCase('r',
2311:                            this .configuration.upperCaseTags,
2312:                            this .configuration.xmlTags), linelen++);
2313:
2314:                    if (this .configuration.xmlOut) {
2315:                        printString(" />");
2316:                    } else {
2317:                        addC('>', linelen++);
2318:                    }
2319:
2320:                    if (this .configuration.indentContent) {
2321:                        condFlushLine(fout, indent);
2322:                    }
2323:
2324:                    // PrintVertSpacer(fout, indent);
2325:
2326:                    // condFlushLine(fout, indent);
2327:
2328:                    // print the h2 element
2329:                    printTree(fout, mode,
2330:                            (this .configuration.indentContent ? indent
2331:                                    + this .configuration.spaces : indent),
2332:                            lexer, slidecontent);
2333:
2334:                    slidecontent = slidecontent.next;
2335:                }
2336:
2337:                // now continue until we reach the next h2
2338:
2339:                last = null;
2340:                content = slidecontent;
2341:
2342:                for (; content != null; content = content.next) {
2343:                    if (content.tag == tt.tagH2) {
2344:                        break;
2345:                    }
2346:
2347:                    // kludge for naked text before block level tag
2348:                    if (last != null
2349:                            && !this .configuration.indentContent
2350:                            && last.type == Node.TEXT_NODE
2351:                            && content.tag != null
2352:                            && TidyUtils.toBoolean(content.tag.model
2353:                                    & Dict.CM_BLOCK)) {
2354:                        flushLine(fout, indent);
2355:                        flushLine(fout, indent);
2356:                    }
2357:
2358:                    printTree(fout, mode,
2359:                            (this .configuration.indentContent ? indent
2360:                                    + this .configuration.spaces : indent),
2361:                            lexer, content);
2362:
2363:                    last = content;
2364:                }
2365:
2366:                slidecontent = content;
2367:
2368:                // now print epilog
2369:
2370:                condFlushLine(fout, indent);
2371:
2372:                printString("<br clear=\"all\">");
2373:                condFlushLine(fout, indent);
2374:
2375:                addC('<', linelen++);
2376:
2377:                addC(TidyUtils.foldCase('h', this .configuration.upperCaseTags,
2378:                        this .configuration.xmlTags), linelen++);
2379:                addC(TidyUtils.foldCase('r', this .configuration.upperCaseTags,
2380:                        this .configuration.xmlTags), linelen++);
2381:
2382:                if (this .configuration.xmlOut) {
2383:                    printString(" />");
2384:                } else {
2385:                    addC('>', linelen++);
2386:                }
2387:
2388:                if (this .configuration.indentContent) {
2389:                    condFlushLine(fout, indent);
2390:                }
2391:
2392:                printNavBar(fout, indent);
2393:
2394:                // end tag for div
2395:                printString("</div>");
2396:                condFlushLine(fout, indent);
2397:            }
2398:
2399:            /**
2400:             * Add meta element for page transition effect, this works on IE but not NS.
2401:             * @param lexer
2402:             * @param root
2403:             * @param duration
2404:             */
2405:            public void addTransitionEffect(Lexer lexer, Node root,
2406:                    double duration) {
2407:                Node head = root.findHEAD(lexer.configuration.tt);
2408:                String transition;
2409:
2410:                transition = "blendTrans(Duration="
2411:                        + (new Double(duration)).toString() + ")";
2412:
2413:                if (head != null) {
2414:                    Node meta = lexer.inferredTag("meta");
2415:                    meta.addAttribute("http-equiv", "Page-Enter");
2416:                    meta.addAttribute("content", transition);
2417:                    head.insertNodeAtStart(meta);
2418:                }
2419:            }
2420:
2421:            /**
2422:             * Creates slides from h2.
2423:             * @param lexer Lexer
2424:             * @param root root node
2425:             */
2426:            public void createSlides(Lexer lexer, Node root) {
2427:                Node body;
2428:                String buf;
2429:
2430:                NumberFormat numberFormat = NumberFormat.getInstance();
2431:                numberFormat.setMinimumIntegerDigits(3);
2432:
2433:                body = root.findBody(lexer.configuration.tt);
2434:                count = countSlides(body);
2435:                slidecontent = body.content;
2436:
2437:                addTransitionEffect(lexer, root, 3.0);
2438:
2439:                for (slide = 1; slide <= count; ++slide) {
2440:                    buf = "slide" + numberFormat.format(slide) + ".html";
2441:
2442:                    try {
2443:                        FileOutputStream fis = new FileOutputStream(buf);
2444:                        Out out = OutFactory.getOut(configuration, fis);
2445:
2446:                        printTree(out, (short) 0, 0, lexer, root);
2447:                        flushLine(out, 0);
2448:                        out.close();
2449:                    } catch (IOException e) {
2450:                        System.err.println(buf + e.toString());
2451:                    }
2452:                }
2453:
2454:                // delete superfluous slides by deleting slideN.html for N = count+1, count+2, etc.
2455:                // until no such file is found.
2456:
2457:                // #427666 - fix by Eric Rossen 02 Aug 00
2458:                while ((new File("slide" + numberFormat.format(slide) + ".html"))
2459:                        .delete()) {
2460:                    ++slide;
2461:                }
2462:            }
2463:
2464:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.