View Javadoc

1   /*
2    *  Java HTML Tidy - JTidy
3    *  HTML parser and pretty printer
4    *
5    *  Copyright (c) 1998-2000 World Wide Web Consortium (Massachusetts
6    *  Institute of Technology, Institut National de Recherche en
7    *  Informatique et en Automatique, Keio University). All Rights
8    *  Reserved.
9    *
10   *  Contributing Author(s):
11   *
12   *     Dave Raggett <dsr@w3.org>
13   *     Andy Quick <ac.quick@sympatico.ca> (translation to Java)
14   *     Gary L Peskin <garyp@firstech.com> (Java development)
15   *     Sami Lempinen <sami@lempinen.net> (release management)
16   *     Fabrizio Giustina <fgiust at users.sourceforge.net>
17   *
18   *  The contributing author(s) would like to thank all those who
19   *  helped with testing, bug fixes, and patience.  This wouldn't
20   *  have been possible without all of you.
21   *
22   *  COPYRIGHT NOTICE:
23   * 
24   *  This software and documentation is provided "as is," and
25   *  the copyright holders and contributing author(s) make no
26   *  representations or warranties, express or implied, including
27   *  but not limited to, warranties of merchantability or fitness
28   *  for any particular purpose or that the use of the software or
29   *  documentation will not infringe any third party patents,
30   *  copyrights, trademarks or other rights. 
31   *
32   *  The copyright holders and contributing author(s) will not be
33   *  liable for any direct, indirect, special or consequential damages
34   *  arising out of any use of the software or documentation, even if
35   *  advised of the possibility of such damage.
36   *
37   *  Permission is hereby granted to use, copy, modify, and distribute
38   *  this source code, or portions hereof, documentation and executables,
39   *  for any purpose, without fee, subject to the following restrictions:
40   *
41   *  1. The origin of this source code must not be misrepresented.
42   *  2. Altered versions must be plainly marked as such and must
43   *     not be misrepresented as being the original source.
44   *  3. This Copyright notice may not be removed or altered from any
45   *     source or altered source distribution.
46   * 
47   *  The copyright holders and contributing author(s) specifically
48   *  permit, without fee, and encourage the use of this source code
49   *  as a component for supporting the Hypertext Markup Language in
50   *  commercial products. If you use this source code in a product,
51   *  acknowledgment is not required but would be appreciated.
52   *
53   */
54  package org.w3c.tidy;
55  
56  import java.io.PrintWriter;
57  import java.text.MessageFormat;
58  import java.text.SimpleDateFormat;
59  import java.util.Date;
60  import java.util.MissingResourceException;
61  import java.util.ResourceBundle;
62  
63  import org.w3c.tidy.TidyMessage.Level;
64  
65  
66  /**
67   * Error/informational message reporter. You should only need to edit the file TidyMessages.properties to localize HTML
68   * tidy.
69   * @author Dave Raggett <a href="mailto:dsr@w3.org">dsr@w3.org </a>
70   * @author Andy Quick <a href="mailto:ac.quick@sympatico.ca">ac.quick@sympatico.ca </a> (translation to Java)
71   * @author Fabrizio Giustina
72   * @version $Revision: 779 $ ($Author: fgiust $)
73   */
74  public final class Report
75  {
76  
77      /**
78       * used to point to Web Accessibility Guidelines.
79       */
80      public static final String ACCESS_URL = "http://www.w3.org/WAI/GL";
81  
82      /**
83       * Release date.
84       */
85      public static final Date RELEASE_DATE = new Date(1096227718000L);
86  
87      /**
88       * Release date String.
89       */
90      public static final String RELEASE_DATE_STRING = new SimpleDateFormat("dd MMM yyyy").format(RELEASE_DATE);
91  
92      /**
93       * invalid entity: missing semicolon.
94       */
95      public static final short MISSING_SEMICOLON = 1;
96  
97      /**
98       * invalid entity: missing semicolon.
99       */
100     public static final short MISSING_SEMICOLON_NCR = 2;
101 
102     /**
103      * invalid entity: unknown entity.
104      */
105     public static final short UNKNOWN_ENTITY = 3;
106 
107     /**
108      * invalid entity: unescaped ampersand.
109      */
110     public static final short UNESCAPED_AMPERSAND = 4;
111 
112     /**
113      * invalid entity: apos undefined in current definition.
114      */
115     public static final short APOS_UNDEFINED = 5;
116 
117     /**
118      * missing an end tag.
119      */
120     public static final short MISSING_ENDTAG_FOR = 6;
121 
122     /**
123      * missing end tag before.
124      */
125     public static final short MISSING_ENDTAG_BEFORE = 7;
126 
127     /**
128      * discarding unexpected element.
129      */
130     public static final short DISCARDING_UNEXPECTED = 8;
131 
132     /**
133      * nested emphasis.
134      */
135     public static final short NESTED_EMPHASIS = 9;
136 
137     /**
138      * non matching end tag.
139      */
140     public static final short NON_MATCHING_ENDTAG = 10;
141 
142     /**
143      * tag not allowed in.
144      */
145     public static final short TAG_NOT_ALLOWED_IN = 11;
146 
147     /**
148      * missing start tag.
149      */
150     public static final short MISSING_STARTTAG = 12;
151 
152     /**
153      * unexpected end tag.
154      */
155     public static final short UNEXPECTED_ENDTAG = 13;
156 
157     /**
158      * unsing br in place of.
159      */
160     public static final short USING_BR_INPLACE_OF = 14;
161 
162     /**
163      * inserting tag.
164      */
165     public static final short INSERTING_TAG = 15;
166 
167     /**
168      * suspected missing quote.
169      */
170     public static final short SUSPECTED_MISSING_QUOTE = 16;
171 
172     /**
173      * missing title element.
174      */
175     public static final short MISSING_TITLE_ELEMENT = 17;
176 
177     /**
178      * duplicate frameset.
179      */
180     public static final short DUPLICATE_FRAMESET = 18;
181 
182     /**
183      * elments can be nested.
184      */
185     public static final short CANT_BE_NESTED = 19;
186 
187     /**
188      * obsolete element.
189      */
190     public static final short OBSOLETE_ELEMENT = 20;
191 
192     /**
193      * proprietary element.
194      */
195     public static final short PROPRIETARY_ELEMENT = 21;
196 
197     /**
198      * unknown element.
199      */
200     public static final short UNKNOWN_ELEMENT = 22;
201 
202     /**
203      * trim empty element.
204      */
205     public static final short TRIM_EMPTY_ELEMENT = 23;
206 
207     /**
208      * coerce to end tag.
209      */
210     public static final short COERCE_TO_ENDTAG = 24;
211 
212     /**
213      * illegal nesting.
214      */
215     public static final short ILLEGAL_NESTING = 25;
216 
217     /**
218      * noframes content.
219      */
220     public static final short NOFRAMES_CONTENT = 26;
221 
222     /**
223      * content after body.
224      */
225     public static final short CONTENT_AFTER_BODY = 27;
226 
227     /**
228      * inconsistent version.
229      */
230     public static final short INCONSISTENT_VERSION = 28;
231 
232     /**
233      * malformed comment.
234      */
235     public static final short MALFORMED_COMMENT = 29;
236 
237     /**
238      * bad coment chars.
239      */
240     public static final short BAD_COMMENT_CHARS = 30;
241 
242     /**
243      * bad xml comment.
244      */
245     public static final short BAD_XML_COMMENT = 31;
246 
247     /**
248      * bad cdata comment.
249      */
250     public static final short BAD_CDATA_CONTENT = 32;
251 
252     /**
253      * inconsistent namespace.
254      */
255     public static final short INCONSISTENT_NAMESPACE = 33;
256 
257     /**
258      * doctype after tags.
259      */
260     public static final short DOCTYPE_AFTER_TAGS = 34;
261 
262     /**
263      * malformed doctype.
264      */
265     public static final short MALFORMED_DOCTYPE = 35;
266 
267     /**
268      * unexpected end of file.
269      */
270     public static final short UNEXPECTED_END_OF_FILE = 36;
271 
272     /**
273      * doctype not upper case.
274      */
275     public static final short DTYPE_NOT_UPPER_CASE = 37;
276 
277     /**
278      * too many element.
279      */
280     public static final short TOO_MANY_ELEMENTS = 38;
281 
282     /**
283      * unescaped element.
284      */
285     public static final short UNESCAPED_ELEMENT = 39;
286 
287     /**
288      * nested quotation.
289      */
290     public static final short NESTED_QUOTATION = 40;
291 
292     /**
293      * element not empty.
294      */
295     public static final short ELEMENT_NOT_EMPTY = 41;
296 
297     /**
298      * encoding IO conflict.
299      */
300     public static final short ENCODING_IO_CONFLICT = 42;
301 
302     /**
303      * mixed content in block.
304      */
305     public static final short MIXED_CONTENT_IN_BLOCK = 43;
306 
307     /**
308      * missing doctype.
309      */
310     public static final short MISSING_DOCTYPE = 44;
311 
312     /**
313      * space preceding xml declaration.
314      */
315     public static final short SPACE_PRECEDING_XMLDECL = 45;
316 
317     /**
318      * too many elements in.
319      */
320     public static final short TOO_MANY_ELEMENTS_IN = 46;
321 
322     /**
323      * unexpected endag in.
324      */
325     public static final short UNEXPECTED_ENDTAG_IN = 47;
326 
327     /**
328      * replacing element.
329      */
330     public static final short REPLACING_ELEMENT = 83;
331 
332     /**
333      * replacing unexcaped element.
334      */
335     public static final short REPLACING_UNEX_ELEMENT = 84;
336 
337     /**
338      * coerce to endtag.
339      */
340     public static final short COERCE_TO_ENDTAG_WARN = 85;
341 
342     /**
343      * attribute: unknown attribute.
344      */
345     public static final short UNKNOWN_ATTRIBUTE = 48;
346 
347     /**
348      * attribute: missing attribute.
349      */
350     public static final short MISSING_ATTRIBUTE = 49;
351 
352     /**
353      * attribute: missing attribute value.
354      */
355     public static final short MISSING_ATTR_VALUE = 50;
356 
357     /**
358      * attribute: bad attribute value.
359      */
360     public static final short BAD_ATTRIBUTE_VALUE = 51;
361 
362     /**
363      * attribute: unexpected gt.
364      */
365     public static final short UNEXPECTED_GT = 52;
366 
367     /**
368      * attribute: proprietary attribute.
369      */
370     public static final short PROPRIETARY_ATTRIBUTE = 53;
371 
372     /**
373      * attribute: proprietary attribute value.
374      */
375     public static final short PROPRIETARY_ATTR_VALUE = 54;
376 
377     /**
378      * attribute: repeated attribute.
379      */
380     public static final short REPEATED_ATTRIBUTE = 55;
381 
382     /**
383      * attribute: missing image map.
384      */
385     public static final short MISSING_IMAGEMAP = 56;
386 
387     /**
388      * attribute: xml attribute value.
389      */
390     public static final short XML_ATTRIBUTE_VALUE = 57;
391 
392     /**
393      * attribute: missing quotemark.
394      */
395     public static final short MISSING_QUOTEMARK = 58;
396 
397     /**
398      * attribute: unexpected quotemark.
399      */
400     public static final short UNEXPECTED_QUOTEMARK = 59;
401 
402     /**
403      * attribute: id and name mismatch.
404      */
405     public static final short ID_NAME_MISMATCH = 60;
406 
407     /**
408      * attribute: backslash in URI.
409      */
410     public static final short BACKSLASH_IN_URI = 61;
411 
412     /**
413      * attribute: fixed backslash.
414      */
415     public static final short FIXED_BACKSLASH = 62;
416 
417     /**
418      * attribute: illegal URI reference.
419      */
420     public static final short ILLEGAL_URI_REFERENCE = 63;
421 
422     /**
423      * attribute: escaped illegal URI.
424      */
425     public static final short ESCAPED_ILLEGAL_URI = 64;
426 
427     /**
428      * attribute: newline in URI.
429      */
430     public static final short NEWLINE_IN_URI = 65;
431 
432     /**
433      * attribute: anchor not unique.
434      */
435     public static final short ANCHOR_NOT_UNIQUE = 66;
436 
437     /**
438      * attribute: entity in id.
439      */
440     public static final short ENTITY_IN_ID = 67;
441 
442     /**
443      * attribute: joining attribute.
444      */
445     public static final short JOINING_ATTRIBUTE = 68;
446 
447     /**
448      * attribute: expected equalsign.
449      */
450     public static final short UNEXPECTED_EQUALSIGN = 69;
451 
452     /**
453      * attribute: attribute value not lower case.
454      */
455     public static final short ATTR_VALUE_NOT_LCASE = 70;
456 
457     /**
458      * attribute: id sintax.
459      */
460     public static final short XML_ID_SYNTAX = 71;
461 
462     /**
463      * attribute: invalid attribute.
464      */
465     public static final short INVALID_ATTRIBUTE = 72;
466 
467     /**
468      * attribute: bad attribute value replaced.
469      */
470     public static final short BAD_ATTRIBUTE_VALUE_REPLACED = 73;
471 
472     /**
473      * attribute: invalid xml id.
474      */
475     public static final short INVALID_XML_ID = 74;
476 
477     /**
478      * attribute: unexpected end of file.
479      */
480     public static final short UNEXPECTED_END_OF_FILE_ATTR = 75;
481 
482     /**
483      * character encoding: vendor specific chars.
484      */
485     public static final short VENDOR_SPECIFIC_CHARS = 76;
486 
487     /**
488      * character encoding: invalid sgml chars.
489      */
490     public static final short INVALID_SGML_CHARS = 77;
491 
492     /**
493      * character encoding: invalid utf8.
494      */
495     public static final short INVALID_UTF8 = 78;
496 
497     /**
498      * character encoding: invalid utf16.
499      */
500     public static final short INVALID_UTF16 = 79;
501 
502     /**
503      * character encoding: encoding mismatch.
504      */
505     public static final short ENCODING_MISMATCH = 80;
506 
507     /**
508      * character encoding: nvalid URI.
509      */
510     public static final short INVALID_URI = 81;
511 
512     /**
513      * character encoding: invalid NCR.
514      */
515     public static final short INVALID_NCR = 82;
516 
517     /**
518      * Constant used for reporting of given doctype.
519      */
520     public static final short DOCTYPE_GIVEN_SUMMARY = 110;
521 
522     /**
523      * Constant used for reporting of version summary.
524      */
525     public static final short REPORT_VERSION_SUMMARY = 111;
526 
527     /**
528      * Constant used for reporting of bad access summary.
529      */
530     public static final short BADACCESS_SUMMARY = 112;
531 
532     /**
533      * Constant used for reporting of bad form summary.
534      */
535     public static final short BADFORM_SUMMARY = 113;
536 
537     /**
538      * accessibility flaw: missing image map.
539      */
540     public static final short MISSING_IMAGE_ALT = 1;
541 
542     /**
543      * accessibility flaw: missing link alt.
544      */
545     public static final short MISSING_LINK_ALT = 2;
546 
547     /**
548      * accessibility flaw: missing summary.
549      */
550     public static final short MISSING_SUMMARY = 4;
551 
552     /**
553      * accessibility flaw: missing image map.
554      */
555     public static final short MISSING_IMAGE_MAP = 8;
556 
557     /**
558      * accessibility flaw: using frames.
559      */
560     public static final short USING_FRAMES = 16;
561 
562     /**
563      * accessibility flaw: using noframes.
564      */
565     public static final short USING_NOFRAMES = 32;
566 
567     /**
568      * presentation flaw: using spacer.
569      */
570     public static final short USING_SPACER = 1;
571 
572     /**
573      * presentation flaw: using layer.
574      */
575     public static final short USING_LAYER = 2;
576 
577     /**
578      * presentation flaw: using nobr.
579      */
580     public static final short USING_NOBR = 4;
581 
582     /**
583      * presentation flaw: using font.
584      */
585     public static final short USING_FONT = 8;
586 
587     /**
588      * presentation flaw: using body.
589      */
590     public static final short USING_BODY = 16;
591 
592     /**
593      * character encoding error: windows chars.
594      */
595     public static final short WINDOWS_CHARS = 1;
596 
597     /**
598      * character encoding error: non ascii.
599      */
600     public static final short NON_ASCII = 2;
601 
602     /**
603      * character encoding error: found utf16.
604      */
605     public static final short FOUND_UTF16 = 4;
606 
607     /**
608      * char has been replaced.
609      */
610     public static final short REPLACED_CHAR = 0;
611 
612     /**
613      * char has been discarder.
614      */
615     public static final short DISCARDED_CHAR = 1;
616 
617     /**
618      * Resource bundle with messages.
619      */
620     private static ResourceBundle res;
621 
622     /**
623      * Printed in GNU Emacs messages.
624      */
625     private String currentFile;
626 
627     /**
628      * message listener for error reporting.
629      */
630     private TidyMessageListener listener;
631 
632     static
633     {
634         try
635         {
636             res = ResourceBundle.getBundle("org/w3c/tidy/TidyMessages");
637         }
638         catch (MissingResourceException e)
639         {
640             throw new Error(e.toString());
641         }
642     }
643 
644     /**
645      * Instantiated only in Tidy() constructor.
646      */
647     protected Report()
648     {
649         super();
650     }
651 
652     /**
653      * Generates a complete message for the warning/error. The message is composed by:
654      * <ul>
655      * <li>position in file</li>
656      * <li>prefix for the error level (warning: | error:)</li>
657      * <li>message read from ResourceBundle</li>
658      * <li>optional parameters added to message using MessageFormat</li>
659      * </ul>
660      * @param errorCode tidy error code
661      * @param lexer Lexer
662      * @param message key for the ResourceBundle
663      * @param params optional parameters added with MessageFormat
664      * @param level message level. One of <code>TidyMessage.LEVEL_ERROR</code>,
665      * <code>TidyMessage.LEVEL_WARNING</code>,<code>TidyMessage.LEVEL_INFO</code>
666      * @return formatted message
667      * @throws MissingResourceException if <code>message</code> key is not available in jtidy resource bundle.
668      * @see TidyMessage
669      */
670     protected String getMessage(int errorCode, Lexer lexer, String message, Object[] params, Level level)
671         throws MissingResourceException
672     {
673         String resource;
674         resource = res.getString(message);
675 
676         String position;
677 
678         if (lexer != null && level != Level.SUMMARY)
679         {
680             position = getPosition(lexer);
681         }
682         else
683         {
684             position = "";
685         }
686 
687         String prefix;
688 
689         if (level == Level.ERROR)
690         {
691             prefix = res.getString("error");
692         }
693         else if (level == Level.WARNING)
694         {
695             prefix = res.getString("warning");
696         }
697         else
698         {
699             prefix = "";
700         }
701 
702         String messageString;
703 
704         if (params != null)
705         {
706             messageString = MessageFormat.format(resource, params);
707         }
708         else
709         {
710             messageString = resource;
711         }
712 
713         if (listener != null)
714         {
715             TidyMessage msg = new TidyMessage(errorCode, (lexer != null) ? lexer.lines : 0, (lexer != null)
716                 ? lexer.columns
717                 : 0, level, messageString);
718             listener.messageReceived(msg);
719         }
720 
721         return position + prefix + messageString;
722     }
723 
724     /**
725      * Prints a message to lexer.errout after calling getMessage().
726      * @param errorCode tidy error code
727      * @param lexer Lexer
728      * @param message key for the ResourceBundle
729      * @param params optional parameters added with MessageFormat
730      * @param level message level. One of <code>TidyMessage.LEVEL_ERROR</code>,
731      * <code>TidyMessage.LEVEL_WARNING</code>,<code>TidyMessage.LEVEL_INFO</code>
732      * @see TidyMessage
733      */
734     private void printMessage(int errorCode, Lexer lexer, String message, Object[] params, Level level)
735     {
736         String resource;
737         try
738         {
739             resource = getMessage(errorCode, lexer, message, params, level);
740         }
741         catch (MissingResourceException e)
742         {
743             lexer.errout.println(e.toString());
744             return;
745         }
746 
747         lexer.errout.println(resource);
748     }
749 
750     /**
751      * Prints a message to errout after calling getMessage(). Used when lexer is not yet defined.
752      * @param errout PrintWriter
753      * @param message key for the ResourceBundle
754      * @param params optional parameters added with MessageFormat
755      * @param level message level. One of <code>TidyMessage.LEVEL_ERROR</code>,
756      * <code>TidyMessage.LEVEL_WARNING</code>,<code>TidyMessage.LEVEL_INFO</code>
757      * @see TidyMessage
758      */
759     private void printMessage(PrintWriter errout, String message, Object[] params, Level level)
760     {
761         String resource;
762         try
763         {
764             resource = getMessage(-1, null, message, params, level);
765         }
766         catch (MissingResourceException e)
767         {
768             errout.println(e.toString());
769             return;
770         }
771         errout.println(resource);
772     }
773 
774     /**
775      * print version information.
776      * @param p printWriter
777      */
778     public void showVersion(PrintWriter p)
779     {
780         printMessage(p, "version_summary", new Object[]{RELEASE_DATE}, Level.SUMMARY);
781     }
782 
783     /**
784      * Returns a formatted tag name handling start and ent tags, nulls, doctypes, and text.
785      * @param tag Node
786      * @return formatted tag name
787      */
788     private String getTagName(Node tag)
789     {
790         if (tag != null)
791         {
792             if (tag.type == Node.START_TAG)
793             {
794                 return "<" + tag.element + ">";
795             }
796             else if (tag.type == Node.END_TAG)
797             {
798                 return "</" + tag.element + ">";
799             }
800             else if (tag.type == Node.DOCTYPE_TAG)
801             {
802                 return "<!DOCTYPE>";
803             }
804             else if (tag.type == Node.TEXT_NODE)
805             {
806                 return "plain text";
807             }
808             else
809             {
810                 return tag.element;
811             }
812         }
813         return "";
814     }
815 
816     /**
817      * Prints an "unknown option" error message. Lexer is not defined when this is called.
818      * @param option unknown option name
819      */
820     public void unknownOption(String option)
821     {
822         try
823         {
824             System.err.println(MessageFormat.format(res.getString("unknown_option"), new Object[]{option}));
825         }
826         catch (MissingResourceException e)
827         {
828             System.err.println(e.toString());
829         }
830     }
831 
832     /**
833      * Prints a "bad argument" error message. Lexer is not defined when this is called.
834      * @param key argument name
835      * @param value bad argument value
836      */
837     public void badArgument(String key, String value)
838     {
839         try
840         {
841             System.err.println(MessageFormat.format(res.getString("bad_argument"), new Object[]{value, key}));
842         }
843         catch (MissingResourceException e)
844         {
845             System.err.println(e.toString());
846         }
847     }
848 
849     /**
850      * Returns a formatted String describing the current position in file.
851      * @param lexer Lexer
852      * @return String position ("line:column")
853      */
854     private String getPosition(Lexer lexer)
855     {
856         try
857         {
858             // Change formatting to be parsable by GNU Emacs
859             if (lexer.configuration.emacs)
860             {
861                 return MessageFormat.format(res.getString("emacs_format"), new Object[]{
862                     this.currentFile,
863                     new Integer(lexer.lines),
864                     new Integer(lexer.columns)})
865                     + " ";
866             }
867             // traditional format
868             return MessageFormat.format(res.getString("line_column"), new Object[]{
869                 new Integer(lexer.lines),
870                 new Integer(lexer.columns)});
871 
872         }
873         catch (MissingResourceException e)
874         {
875             lexer.errout.println(e.toString());
876         }
877         return "";
878     }
879 
880     /**
881      * Prints encoding error messages.
882      * @param lexer Lexer
883      * @param code error code
884      * @param c invalid char
885      */
886     public void encodingError(Lexer lexer, int code, int c)
887     {
888         lexer.warnings++;
889 
890         if (lexer.errors > lexer.configuration.showErrors) // keep quiet after <showErrors> errors
891         {
892             return;
893         }
894 
895         if (lexer.configuration.showWarnings)
896         {
897             String buf = Integer.toHexString(c);
898 
899             // An encoding mismatch is currently treated as a non-fatal error
900             if ((code & ~DISCARDED_CHAR) == ENCODING_MISMATCH)
901             {
902                 // actual encoding passed in "c"
903                 lexer.badChars |= ENCODING_MISMATCH;
904                 printMessage(
905                     code,
906                     lexer,
907                     "encoding_mismatch",
908                     new Object[]{
909                         lexer.configuration.getInCharEncodingName(),
910                         ParsePropertyImpl.CHAR_ENCODING.getFriendlyName(null, new Integer(c), lexer.configuration)},
911                     Level.WARNING);
912             }
913             else if ((code & ~DISCARDED_CHAR) == VENDOR_SPECIFIC_CHARS)
914             {
915                 lexer.badChars |= VENDOR_SPECIFIC_CHARS;
916                 printMessage(
917                     code,
918                     lexer,
919                     "invalid_char",
920                     new Object[]{new Integer(code & DISCARDED_CHAR), buf},
921                     Level.WARNING);
922             }
923             else if ((code & ~DISCARDED_CHAR) == INVALID_SGML_CHARS)
924             {
925                 lexer.badChars |= INVALID_SGML_CHARS;
926                 printMessage(
927                     code,
928                     lexer,
929                     "invalid_char",
930                     new Object[]{new Integer(code & DISCARDED_CHAR), buf},
931                     Level.WARNING);
932             }
933             else if ((code & ~DISCARDED_CHAR) == INVALID_UTF8)
934             {
935                 lexer.badChars |= INVALID_UTF8;
936                 printMessage(
937                     code,
938                     lexer,
939                     "invalid_utf8",
940                     new Object[]{new Integer(code & DISCARDED_CHAR), buf},
941                     Level.WARNING);
942             }
943 
944             else if ((code & ~DISCARDED_CHAR) == INVALID_UTF16)
945             {
946                 lexer.badChars |= INVALID_UTF16;
947                 printMessage(
948                     code,
949                     lexer,
950                     "invalid_utf16",
951                     new Object[]{new Integer(code & DISCARDED_CHAR), buf},
952                     Level.WARNING);
953 
954             }
955 
956             else if ((code & ~DISCARDED_CHAR) == INVALID_NCR)
957             {
958                 lexer.badChars |= INVALID_NCR;
959                 printMessage(
960                     code,
961                     lexer,
962                     "invalid_ncr",
963                     new Object[]{new Integer(code & DISCARDED_CHAR), buf},
964                     Level.WARNING);
965             }
966 
967         }
968     }
969 
970     /**
971      * Prints entity error messages.
972      * @param lexer Lexer
973      * @param code error code
974      * @param entity invalid entity String
975      * @param c invalid char
976      */
977     public void entityError(Lexer lexer, short code, String entity, int c)
978     {
979         lexer.warnings++;
980 
981         if (lexer.errors > lexer.configuration.showErrors) // keep quiet after <showErrors> errors
982         {
983             return;
984         }
985 
986         if (lexer.configuration.showWarnings)
987         {
988             switch (code)
989             {
990                 case MISSING_SEMICOLON :
991                     printMessage(code, lexer, "missing_semicolon", new Object[]{entity}, Level.WARNING);
992                     break;
993                 case MISSING_SEMICOLON_NCR :
994                     printMessage(code, lexer, "missing_semicolon_ncr", new Object[]{entity}, Level.WARNING);
995                     break;
996                 case UNKNOWN_ENTITY :
997                     printMessage(code, lexer, "unknown_entity", new Object[]{entity}, Level.WARNING);
998                     break;
999                 case UNESCAPED_AMPERSAND :
1000                     printMessage(code, lexer, "unescaped_ampersand", null, Level.WARNING);
1001                     break;
1002                 case APOS_UNDEFINED :
1003                     printMessage(code, lexer, "apos_undefined", null, Level.WARNING);
1004                     break;
1005                 default :
1006                     // should not reach here
1007                     break;
1008             }
1009         }
1010     }
1011 
1012     /**
1013      * Prints error messages for attributes.
1014      * @param lexer Lexer
1015      * @param node current tag
1016      * @param attribute attribute
1017      * @param code error code
1018      */
1019     public void attrError(Lexer lexer, Node node, AttVal attribute, short code)
1020     {
1021         if (code == UNEXPECTED_GT)
1022         {
1023             lexer.errors++;
1024         }
1025         else
1026         {
1027             lexer.warnings++;
1028         }
1029 
1030         if (lexer.errors > lexer.configuration.showErrors) // keep quiet after <showErrors> errors
1031         {
1032             return;
1033         }
1034 
1035         if (code == UNEXPECTED_GT) // error
1036         {
1037             printMessage(code, lexer, "unexpected_gt", new Object[]{getTagName(node)}, Level.ERROR);
1038         }
1039 
1040         if (!lexer.configuration.showWarnings) // warnings
1041         {
1042             return;
1043         }
1044 
1045         switch (code)
1046         {
1047             case UNKNOWN_ATTRIBUTE :
1048                 printMessage(code, lexer, "unknown_attribute", new Object[]{attribute.attribute}, Level.WARNING);
1049                 break;
1050 
1051             case MISSING_ATTRIBUTE :
1052                 printMessage(
1053                     code,
1054                     lexer,
1055                     "missing_attribute",
1056                     new Object[]{getTagName(node), attribute.attribute},
1057                     Level.WARNING);
1058                 break;
1059 
1060             case MISSING_ATTR_VALUE :
1061                 printMessage(
1062                     code,
1063                     lexer,
1064                     "missing_attr_value",
1065                     new Object[]{getTagName(node), attribute.attribute},
1066                     Level.WARNING);
1067                 break;
1068 
1069             case MISSING_IMAGEMAP :
1070                 printMessage(code, lexer, "missing_imagemap", new Object[]{getTagName(node)}, Level.WARNING);
1071                 lexer.badAccess |= MISSING_IMAGE_MAP;
1072                 break;
1073 
1074             case BAD_ATTRIBUTE_VALUE :
1075                 printMessage(code, lexer, "bad_attribute_value", new Object[]{
1076                     getTagName(node),
1077                     attribute.attribute,
1078                     attribute.value}, Level.WARNING);
1079                 break;
1080 
1081             case XML_ID_SYNTAX :
1082                 printMessage(
1083                     code,
1084                     lexer,
1085                     "xml_id_sintax",
1086                     new Object[]{getTagName(node), attribute.attribute},
1087                     Level.WARNING);
1088                 break;
1089 
1090             case XML_ATTRIBUTE_VALUE :
1091                 printMessage(
1092                     code,
1093                     lexer,
1094                     "xml_attribute_value",
1095                     new Object[]{getTagName(node), attribute.attribute},
1096                     Level.WARNING);
1097                 break;
1098 
1099             case UNEXPECTED_QUOTEMARK :
1100                 printMessage(code, lexer, "unexpected_quotemark", new Object[]{getTagName(node)}, Level.WARNING);
1101                 break;
1102 
1103             case MISSING_QUOTEMARK :
1104                 printMessage(code, lexer, "missing_quotemark", new Object[]{getTagName(node)}, Level.WARNING);
1105                 break;
1106 
1107             case REPEATED_ATTRIBUTE :
1108                 printMessage(code, lexer, "repeated_attribute", new Object[]{
1109                     getTagName(node),
1110                     attribute.value,
1111                     attribute.attribute}, Level.WARNING);
1112                 break;
1113 
1114             case PROPRIETARY_ATTR_VALUE :
1115                 printMessage(
1116                     code,
1117                     lexer,
1118                     "proprietary_attr_value",
1119                     new Object[]{getTagName(node), attribute.value},
1120                     Level.WARNING);
1121                 break;
1122 
1123             case PROPRIETARY_ATTRIBUTE :
1124                 printMessage(
1125                     code,
1126                     lexer,
1127                     "proprietary_attribute",
1128                     new Object[]{getTagName(node), attribute.attribute},
1129                     Level.WARNING);
1130                 break;
1131 
1132             case UNEXPECTED_END_OF_FILE :
1133                 // on end of file adjust reported position to end of input
1134                 lexer.lines = lexer.in.getCurline();
1135                 lexer.columns = lexer.in.getCurcol();
1136                 printMessage(code, lexer, "unexpected_end_of_file", new Object[]{getTagName(node)}, Level.WARNING);
1137                 break;
1138 
1139             case ID_NAME_MISMATCH :
1140                 printMessage(code, lexer, "id_name_mismatch", new Object[]{getTagName(node)}, Level.WARNING);
1141                 break;
1142 
1143             case BACKSLASH_IN_URI :
1144                 printMessage(code, lexer, "backslash_in_uri", new Object[]{getTagName(node)}, Level.WARNING);
1145                 break;
1146 
1147             case FIXED_BACKSLASH :
1148                 printMessage(code, lexer, "fixed_backslash", new Object[]{getTagName(node)}, Level.WARNING);
1149                 break;
1150 
1151             case ILLEGAL_URI_REFERENCE :
1152                 printMessage(code, lexer, "illegal_uri_reference", new Object[]{getTagName(node)}, Level.WARNING);
1153                 break;
1154 
1155             case ESCAPED_ILLEGAL_URI :
1156                 printMessage(code, lexer, "escaped_illegal_uri", new Object[]{getTagName(node)}, Level.WARNING);
1157                 break;
1158 
1159             case NEWLINE_IN_URI :
1160                 printMessage(code, lexer, "newline_in_uri", new Object[]{getTagName(node)}, Level.WARNING);
1161                 break;
1162 
1163             case ANCHOR_NOT_UNIQUE :
1164                 printMessage(
1165                     code,
1166                     lexer,
1167                     "anchor_not_unique",
1168                     new Object[]{getTagName(node), attribute.value},
1169                     Level.WARNING);
1170                 break;
1171 
1172             case ENTITY_IN_ID :
1173                 printMessage(code, lexer, "entity_in_id", null, Level.WARNING);
1174                 break;
1175 
1176             case JOINING_ATTRIBUTE :
1177                 printMessage(
1178                     code,
1179                     lexer,
1180                     "joining_attribute",
1181                     new Object[]{getTagName(node), attribute.attribute},
1182                     Level.WARNING);
1183                 break;
1184 
1185             case UNEXPECTED_EQUALSIGN :
1186                 printMessage(code, lexer, "expected_equalsign", new Object[]{getTagName(node)}, Level.WARNING);
1187                 break;
1188 
1189             case ATTR_VALUE_NOT_LCASE :
1190                 printMessage(code, lexer, "attr_value_not_lcase", new Object[]{
1191                     getTagName(node),
1192                     attribute.value,
1193                     attribute.attribute}, Level.WARNING);
1194                 break;
1195 
1196             default :
1197                 break;
1198         }
1199     }
1200 
1201     /**
1202      * Prints warnings.
1203      * @param lexer Lexer
1204      * @param element parent/missing tag
1205      * @param node current tag
1206      * @param code error code
1207      */
1208     public void warning(Lexer lexer, Node element, Node node, short code)
1209     {
1210 
1211         TagTable tt = lexer.configuration.tt;
1212         if (!((code == DISCARDING_UNEXPECTED) && lexer.badForm != 0)) // lexer->errors++; already done in BadForm()
1213         {
1214             lexer.warnings++;
1215         }
1216 
1217         // keep quiet after <showErrors> errors
1218         if (lexer.errors > lexer.configuration.showErrors)
1219         {
1220             return;
1221         }
1222 
1223         if (lexer.configuration.showWarnings)
1224         {
1225             switch (code)
1226             {
1227                 case MISSING_ENDTAG_FOR :
1228                     printMessage(code, lexer, "missing_endtag_for", new Object[]{element.element}, Level.WARNING);
1229                     break;
1230 
1231                 case MISSING_ENDTAG_BEFORE :
1232                     printMessage(
1233                         code,
1234                         lexer,
1235                         "missing_endtag_before",
1236                         new Object[]{element.element, getTagName(node)},
1237                         Level.WARNING);
1238                     break;
1239 
1240                 case DISCARDING_UNEXPECTED :
1241                     if (lexer.badForm == 0)
1242                     {
1243                         // the case for when this is an error not a warning, is handled later
1244                         printMessage(
1245                             code,
1246                             lexer,
1247                             "discarding_unexpected",
1248                             new Object[]{getTagName(node)},
1249                             Level.WARNING);
1250                     }
1251                     break;
1252 
1253                 case NESTED_EMPHASIS :
1254                     printMessage(code, lexer, "nested_emphasis", new Object[]{getTagName(node)}, Level.INFO);
1255                     break;
1256 
1257                 case COERCE_TO_ENDTAG :
1258                     printMessage(code, lexer, "coerce_to_endtag", new Object[]{element.element}, Level.INFO);
1259                     break;
1260 
1261                 case NON_MATCHING_ENDTAG :
1262                     printMessage(
1263                         code,
1264                         lexer,
1265                         "non_matching_endtag",
1266                         new Object[]{getTagName(node), element.element},
1267                         Level.WARNING);
1268                     break;
1269 
1270                 case TAG_NOT_ALLOWED_IN :
1271                     printMessage(
1272                         code,
1273                         lexer,
1274                         "tag_not_allowed_in",
1275                         new Object[]{getTagName(node), element.element},
1276                         Level.WARNING);
1277                     break;
1278 
1279                 case DOCTYPE_AFTER_TAGS :
1280                     printMessage(code, lexer, "doctype_after_tags", null, Level.WARNING);
1281                     break;
1282 
1283                 case MISSING_STARTTAG :
1284                     printMessage(code, lexer, "missing_starttag", new Object[]{node.element}, Level.WARNING);
1285                     break;
1286 
1287                 case UNEXPECTED_ENDTAG :
1288                     if (element != null)
1289                     {
1290                         printMessage(
1291                             code,
1292                             lexer,
1293                             "unexpected_endtag_in",
1294                             new Object[]{node.element, element.element},
1295                             Level.WARNING);
1296                     }
1297                     else
1298                     {
1299                         printMessage(code, lexer, "unexpected_endtag", new Object[]{node.element}, Level.WARNING);
1300                     }
1301                     break;
1302 
1303                 case TOO_MANY_ELEMENTS :
1304                     if (element != null)
1305                     {
1306                         printMessage(
1307                             code,
1308                             lexer,
1309                             "too_many_elements_in",
1310                             new Object[]{node.element, element.element},
1311                             Level.WARNING);
1312                     }
1313                     else
1314                     {
1315                         printMessage(code, lexer, "too_many_elements", new Object[]{node.element}, Level.WARNING);
1316                     }
1317                     break;
1318 
1319                 case USING_BR_INPLACE_OF :
1320                     printMessage(code, lexer, "using_br_inplace_of", new Object[]{getTagName(node)}, Level.WARNING);
1321                     break;
1322 
1323                 case INSERTING_TAG :
1324                     printMessage(code, lexer, "inserting_tag", new Object[]{node.element}, Level.WARNING);
1325                     break;
1326 
1327                 case CANT_BE_NESTED :
1328                     printMessage(code, lexer, "cant_be_nested", new Object[]{getTagName(node)}, Level.WARNING);
1329                     break;
1330 
1331                 case PROPRIETARY_ELEMENT :
1332                     printMessage(code, lexer, "proprietary_element", new Object[]{getTagName(node)}, Level.WARNING);
1333 
1334                     if (node.tag == tt.tagLayer)
1335                     {
1336                         lexer.badLayout |= USING_LAYER;
1337                     }
1338                     else if (node.tag == tt.tagSpacer)
1339                     {
1340                         lexer.badLayout |= USING_SPACER;
1341                     }
1342                     else if (node.tag == tt.tagNobr)
1343                     {
1344                         lexer.badLayout |= USING_NOBR;
1345                     }
1346                     break;
1347 
1348                 case OBSOLETE_ELEMENT :
1349                     if (element.tag != null && (element.tag.model & Dict.CM_OBSOLETE) != 0)
1350                     {
1351                         printMessage(code, lexer, "obsolete_element", new Object[]{
1352                             getTagName(element),
1353                             getTagName(node)}, Level.WARNING);
1354                     }
1355                     else
1356                     {
1357                         printMessage(code, lexer, "replacing_element", new Object[]{
1358                             getTagName(element),
1359                             getTagName(node)}, Level.WARNING);
1360                     }
1361                     break;
1362 
1363                 case UNESCAPED_ELEMENT :
1364                     printMessage(code, lexer, "unescaped_element", new Object[]{getTagName(element)}, Level.WARNING);
1365                     break;
1366 
1367                 case TRIM_EMPTY_ELEMENT :
1368                     printMessage(code, lexer, "trim_empty_element", new Object[]{getTagName(element)}, Level.WARNING);
1369                     break;
1370 
1371                 case MISSING_TITLE_ELEMENT :
1372                     printMessage(code, lexer, "missing_title_element", null, Level.WARNING);
1373                     break;
1374 
1375                 case ILLEGAL_NESTING :
1376                     printMessage(code, lexer, "illegal_nesting", new Object[]{getTagName(element)}, Level.WARNING);
1377                     break;
1378 
1379                 case NOFRAMES_CONTENT :
1380                     printMessage(code, lexer, "noframes_content", new Object[]{getTagName(node)}, Level.WARNING);
1381                     break;
1382 
1383                 case INCONSISTENT_VERSION :
1384                     printMessage(code, lexer, "inconsistent_version", null, Level.WARNING);
1385                     break;
1386 
1387                 case MALFORMED_DOCTYPE :
1388                     printMessage(code, lexer, "malformed_doctype", null, Level.WARNING);
1389                     break;
1390 
1391                 case CONTENT_AFTER_BODY :
1392                     printMessage(code, lexer, "content_after_body", null, Level.WARNING);
1393                     break;
1394 
1395                 case MALFORMED_COMMENT :
1396                     printMessage(code, lexer, "malformed_comment", null, Level.WARNING);
1397                     break;
1398 
1399                 case BAD_COMMENT_CHARS :
1400                     printMessage(code, lexer, "bad_comment_chars", null, Level.WARNING);
1401                     break;
1402 
1403                 case BAD_XML_COMMENT :
1404                     printMessage(code, lexer, "bad_xml_comment", null, Level.WARNING);
1405                     break;
1406 
1407                 case BAD_CDATA_CONTENT :
1408                     printMessage(code, lexer, "bad_cdata_content", null, Level.WARNING);
1409                     break;
1410 
1411                 case INCONSISTENT_NAMESPACE :
1412                     printMessage(code, lexer, "inconsistent_namespace", null, Level.WARNING);
1413                     break;
1414 
1415                 case DTYPE_NOT_UPPER_CASE :
1416                     printMessage(code, lexer, "dtype_not_upper_case", null, Level.WARNING);
1417                     break;
1418 
1419                 case UNEXPECTED_END_OF_FILE :
1420                     // on end of file adjust reported position to end of input
1421                     lexer.lines = lexer.in.getCurline();
1422                     lexer.columns = lexer.in.getCurcol();
1423                     printMessage(
1424                         code,
1425                         lexer,
1426                         "unexpected_end_of_file",
1427                         new Object[]{getTagName(element)},
1428                         Level.WARNING);
1429                     break;
1430 
1431                 case NESTED_QUOTATION :
1432                     printMessage(code, lexer, "nested_quotation", null, Level.WARNING);
1433                     break;
1434 
1435                 case ELEMENT_NOT_EMPTY :
1436                     printMessage(code, lexer, "element_not_empty", new Object[]{getTagName(element)}, Level.WARNING);
1437                     break;
1438 
1439                 case MISSING_DOCTYPE :
1440                     printMessage(code, lexer, "missing_doctype", null, Level.WARNING);
1441                     break;
1442 
1443                 default :
1444                     break;
1445             }
1446         }
1447 
1448         if ((code == DISCARDING_UNEXPECTED) && lexer.badForm != 0)
1449         {
1450             // the case for when this is a warning not an error, is handled earlier
1451             printMessage(code, lexer, "discarding_unexpected", new Object[]{getTagName(node)}, Level.ERROR);
1452         }
1453 
1454     }
1455 
1456     /**
1457      * Prints errors.
1458      * @param lexer Lexer
1459      * @param element parent/missing tag
1460      * @param node current tag
1461      * @param code error code
1462      */
1463     public void error(Lexer lexer, Node element, Node node, short code)
1464     {
1465         lexer.errors++;
1466 
1467         // keep quiet after <showErrors> errors
1468         if (lexer.errors > lexer.configuration.showErrors)
1469         {
1470             return;
1471         }
1472 
1473         if (code == SUSPECTED_MISSING_QUOTE)
1474         {
1475             printMessage(code, lexer, "suspected_missing_quote", null, Level.ERROR);
1476         }
1477         else if (code == DUPLICATE_FRAMESET)
1478         {
1479             printMessage(code, lexer, "duplicate_frameset", null, Level.ERROR);
1480         }
1481         else if (code == UNKNOWN_ELEMENT)
1482         {
1483             printMessage(code, lexer, "unknown_element", new Object[]{getTagName(node)}, Level.ERROR);
1484         }
1485         else if (code == UNEXPECTED_ENDTAG)
1486         {
1487             if (element != null)
1488             {
1489                 printMessage(
1490                     code,
1491                     lexer,
1492                     "unexpected_endtag_in",
1493                     new Object[]{node.element, element.element},
1494                     Level.ERROR);
1495             }
1496             else
1497             {
1498                 printMessage(code, lexer, "unexpected_endtag", new Object[]{node.element}, Level.ERROR);
1499             }
1500         }
1501     }
1502 
1503     /**
1504      * Prints error summary.
1505      * @param lexer Lexer
1506      */
1507     public void errorSummary(Lexer lexer)
1508     {
1509         // adjust badAccess to that its null if frames are ok
1510         if ((lexer.badAccess & (USING_FRAMES | USING_NOFRAMES)) != 0)
1511         {
1512             if (!(((lexer.badAccess & USING_FRAMES) != 0) && ((lexer.badAccess & USING_NOFRAMES) == 0)))
1513             {
1514                 lexer.badAccess &= ~(USING_FRAMES | USING_NOFRAMES);
1515             }
1516         }
1517         if (lexer.badChars != 0)
1518         {
1519             if ((lexer.badChars & VENDOR_SPECIFIC_CHARS) != 0)
1520             {
1521                 int encodingChoiche = 0;
1522 
1523                 if ("Cp1252".equals(lexer.configuration.getInCharEncodingName()))
1524                 {
1525                     encodingChoiche = 1;
1526                 }
1527                 else if ("MacRoman".equals(lexer.configuration.getInCharEncodingName()))
1528                 {
1529                     encodingChoiche = 2;
1530                 }
1531 
1532                 printMessage(VENDOR_SPECIFIC_CHARS, lexer, "vendor_specific_chars_summary", new Object[]{new Integer(
1533                     encodingChoiche)}, Level.SUMMARY);
1534             }
1535 
1536             if ((lexer.badChars & INVALID_SGML_CHARS) != 0 || (lexer.badChars & INVALID_NCR) != 0)
1537             {
1538                 int encodingChoiche = 0;
1539 
1540                 if ("Cp1252".equals(lexer.configuration.getInCharEncodingName()))
1541                 {
1542                     encodingChoiche = 1;
1543                 }
1544                 else if ("MacRoman".equals(lexer.configuration.getInCharEncodingName()))
1545                 {
1546                     encodingChoiche = 2;
1547                 }
1548 
1549                 printMessage(INVALID_SGML_CHARS, lexer, "invalid_sgml_chars_summary", new Object[]{new Integer(
1550                     encodingChoiche)}, Level.SUMMARY);
1551             }
1552 
1553             if ((lexer.badChars & INVALID_UTF8) != 0)
1554             {
1555                 printMessage(INVALID_UTF8, lexer, "invalid_utf8_summary", null, Level.SUMMARY);
1556             }
1557 
1558             if ((lexer.badChars & INVALID_UTF16) != 0)
1559             {
1560                 printMessage(INVALID_UTF16, lexer, "invalid_utf16_summary", null, Level.SUMMARY);
1561             }
1562 
1563             if ((lexer.badChars & INVALID_URI) != 0)
1564             {
1565                 printMessage(INVALID_URI, lexer, "invaliduri_summary", null, Level.SUMMARY);
1566             }
1567         }
1568 
1569         if (lexer.badForm != 0)
1570         {
1571             printMessage(BADFORM_SUMMARY, lexer, "badform_summary", null, Level.SUMMARY);
1572         }
1573 
1574         if (lexer.badAccess != 0)
1575         {
1576             if ((lexer.badAccess & MISSING_SUMMARY) != 0)
1577             {
1578                 printMessage(MISSING_SUMMARY, lexer, "badaccess_missing_summary", null, Level.SUMMARY);
1579             }
1580 
1581             if ((lexer.badAccess & MISSING_IMAGE_ALT) != 0)
1582             {
1583                 printMessage(MISSING_IMAGE_ALT, lexer, "badaccess_missing_image_alt", null, Level.SUMMARY);
1584             }
1585 
1586             if ((lexer.badAccess & MISSING_IMAGE_MAP) != 0)
1587             {
1588                 printMessage(MISSING_IMAGE_MAP, lexer, "badaccess_missing_image_map", null, Level.SUMMARY);
1589             }
1590 
1591             if ((lexer.badAccess & MISSING_LINK_ALT) != 0)
1592             {
1593                 printMessage(MISSING_LINK_ALT, lexer, "badaccess_missing_link_alt", null, Level.SUMMARY);
1594             }
1595 
1596             if (((lexer.badAccess & USING_FRAMES) != 0) && ((lexer.badAccess & USING_NOFRAMES) == 0))
1597             {
1598                 printMessage(USING_FRAMES, lexer, "badaccess_frames", null, Level.SUMMARY);
1599             }
1600 
1601             printMessage(BADACCESS_SUMMARY, lexer, "badaccess_summary", new Object[]{ACCESS_URL}, Level.SUMMARY);
1602         }
1603 
1604         if (lexer.badLayout != 0)
1605         {
1606             if ((lexer.badLayout & USING_LAYER) != 0)
1607             {
1608                 printMessage(USING_LAYER, lexer, "badlayout_using_layer", null, Level.SUMMARY);
1609             }
1610 
1611             if ((lexer.badLayout & USING_SPACER) != 0)
1612             {
1613                 printMessage(USING_SPACER, lexer, "badlayout_using_spacer", null, Level.SUMMARY);
1614             }
1615 
1616             if ((lexer.badLayout & USING_FONT) != 0)
1617             {
1618                 printMessage(USING_FONT, lexer, "badlayout_using_font", null, Level.SUMMARY);
1619             }
1620 
1621             if ((lexer.badLayout & USING_NOBR) != 0)
1622             {
1623                 printMessage(USING_NOBR, lexer, "badlayout_using_nobr", null, Level.SUMMARY);
1624             }
1625 
1626             if ((lexer.badLayout & USING_BODY) != 0)
1627             {
1628                 printMessage(USING_BODY, lexer, "badlayout_using_body", null, Level.SUMMARY);
1629             }
1630         }
1631     }
1632 
1633     /**
1634      * Prints the "unknown option" message.
1635      * @param errout PrintWriter
1636      * @param c invalid option char
1637      */
1638     public void unknownOption(PrintWriter errout, char c)
1639     {
1640         printMessage(errout, "unrecognized_option", new Object[]{new String(new char[]{c})}, Level.ERROR);
1641     }
1642 
1643     /**
1644      * Prints the "unknown file" message.
1645      * @param errout PrintWriter
1646      * @param file invalid file name
1647      */
1648     public void unknownFile(PrintWriter errout, String file)
1649     {
1650         printMessage(errout, "unknown_file", new Object[]{"Tidy", file}, Level.ERROR);
1651     }
1652 
1653     /**
1654      * Prints the "needs author intervention" message.
1655      * @param errout PrintWriter
1656      */
1657     public void needsAuthorIntervention(PrintWriter errout)
1658     {
1659         printMessage(errout, "needs_author_intervention", null, Level.SUMMARY);
1660     }
1661 
1662     /**
1663      * Prints the "missing body" message.
1664      * @param errout PrintWriter
1665      */
1666     public void missingBody(PrintWriter errout)
1667     {
1668         printMessage(errout, "missing_body", null, Level.ERROR);
1669     }
1670 
1671     /**
1672      * Prints the number of generated slides.
1673      * @param errout PrintWriter
1674      * @param count slides count
1675      */
1676     public void reportNumberOfSlides(PrintWriter errout, int count)
1677     {
1678         printMessage(errout, "slides_found", new Object[]{new Integer(count)}, Level.SUMMARY);
1679     }
1680 
1681     /**
1682      * Prints tidy general info.
1683      * @param errout PrintWriter
1684      */
1685     public void generalInfo(PrintWriter errout)
1686     {
1687         printMessage(errout, "general_info", null, Level.SUMMARY);
1688     }
1689 
1690     /**
1691      * Prints tidy hello message.
1692      * @param errout PrintWriter
1693      */
1694     public void helloMessage(PrintWriter errout)
1695     {
1696         printMessage(errout, "hello_message", new Object[]{Report.RELEASE_DATE, this.currentFile}, Level.SUMMARY);
1697     }
1698 
1699     /**
1700      * Sets the current file name.
1701      * @param filename current file.
1702      */
1703     public void setFilename(String filename)
1704     {
1705         this.currentFile = filename; // for use with Gnu Emacs
1706     }
1707 
1708     /**
1709      * Prints information for html version in input file.
1710      * @param errout PrintWriter
1711      * @param lexer Lexer
1712      * @param filename file name
1713      * @param doctype doctype Node
1714      */
1715     public void reportVersion(PrintWriter errout, Lexer lexer, String filename, Node doctype)
1716     {
1717         int i, c;
1718         int state = 0;
1719         String vers = lexer.htmlVersionName();
1720         int[] cc = new int[1];
1721 
1722         // adjust reported position to first line
1723         lexer.lines = 1;
1724         lexer.columns = 1;
1725 
1726         if (doctype != null)
1727         {
1728 
1729             StringBuffer doctypeBuffer = new StringBuffer();
1730             for (i = doctype.start; i < doctype.end; ++i)
1731             {
1732                 c = doctype.textarray[i];
1733 
1734                 // look for UTF-8 multibyte character
1735                 if (c < 0)
1736                 {
1737                     i += PPrint.getUTF8(doctype.textarray, i, cc);
1738                     c = cc[0];
1739                 }
1740 
1741                 if (c == '"')
1742                 {
1743                     ++state;
1744                 }
1745                 else if (state == 1)
1746                 {
1747                     doctypeBuffer.append((char) c);
1748                 }
1749             }
1750 
1751             printMessage(
1752                 DOCTYPE_GIVEN_SUMMARY,
1753                 lexer,
1754                 "doctype_given",
1755                 new Object[]{filename, doctypeBuffer},
1756                 Level.SUMMARY);
1757         }
1758 
1759         printMessage(REPORT_VERSION_SUMMARY, lexer, "report_version", new Object[]{
1760             filename,
1761             (vers != null ? vers : "HTML proprietary")}, Level.SUMMARY);
1762     }
1763 
1764     /**
1765      * Prints the number of error/warnings found.
1766      * @param errout PrintWriter
1767      * @param lexer Lexer
1768      */
1769     public void reportNumWarnings(PrintWriter errout, Lexer lexer)
1770     {
1771         if (lexer.warnings > 0 || lexer.errors > 0)
1772         {
1773             printMessage(
1774                 errout,
1775                 "num_warnings",
1776                 new Object[]{new Integer(lexer.warnings), new Integer(lexer.errors)},
1777                 Level.SUMMARY);
1778         }
1779         else
1780         {
1781             printMessage(errout, "no_warnings", null, Level.SUMMARY);
1782         }
1783     }
1784 
1785     /**
1786      * Prints tidy help.
1787      * @param out PrintWriter
1788      */
1789     public void helpText(PrintWriter out)
1790     {
1791         printMessage(out, "help_text", new Object[]{"Tidy", RELEASE_DATE}, Level.SUMMARY);
1792     }
1793 
1794     /**
1795      * Prints the "bad tree" message.
1796      * @param errout PrintWriter
1797      */
1798     public void badTree(PrintWriter errout)
1799     {
1800         printMessage(errout, "bad_tree", null, Level.ERROR);
1801     }
1802 
1803     /**
1804      * Adds a message listener.
1805      * @param listener TidyMessageListener
1806      */
1807     public void addMessageListener(TidyMessageListener listener)
1808     {
1809         this.listener = listener;
1810     }
1811 }