/* * Java HTML Tidy - JTidy * HTML parser and pretty printer * * Copyright (c) 1998-2000 World Wide Web Consortium (Massachusetts * Institute of Technology, Institut National de Recherche en * Informatique et en Automatique, Keio University). All Rights * Reserved. * * Contributing Author(s): * * Dave Raggett <dsr@w3.org> * Andy Quick <ac.quick@sympatico.ca> (translation to Java) * Gary L Peskin <garyp@firstech.com> (Java development) * Sami Lempinen <sami@lempinen.net> (release management) * Fabrizio Giustina <fgiust at users.sourceforge.net> * * The contributing author(s) would like to thank all those who * helped with testing, bug fixes, and patience. This wouldn't * have been possible without all of you. * * COPYRIGHT NOTICE: * * This software and documentation is provided "as is," and * the copyright holders and contributing author(s) make no * representations or warranties, express or implied, including * but not limited to, warranties of merchantability or fitness * for any particular purpose or that the use of the software or * documentation will not infringe any third party patents, * copyrights, trademarks or other rights. * * The copyright holders and contributing author(s) will not be * liable for any direct, indirect, special or consequential damages * arising out of any use of the software or documentation, even if * advised of the possibility of such damage. * * Permission is hereby granted to use, copy, modify, and distribute * this source code, or portions hereof, documentation and executables, * for any purpose, without fee, subject to the following restrictions: * * 1. The origin of this source code must not be misrepresented. * 2. Altered versions must be plainly marked as such and must * not be misrepresented as being the original source. * 3. This Copyright notice may not be removed or altered from any * source or altered source distribution. * * The copyright holders and contributing author(s) specifically * permit, without fee, and encourage the use of this source code * as a component for supporting the Hypertext Markup Language in * commercial products. If you use this source code in a product, * acknowledgment is not required but would be appreciated. * */ package org.w3c.tidy; import java.io.InputStream; import java.io.PrintWriter; import java.text.MessageFormat; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import org.w3c.tidy.TidyMessage.Level; /** * Error/informational message reporter. You should only need to edit the file TidyMessages.properties to localize HTML * tidy. * @author Dave Raggett <a href="mailto:dsr@w3.org">dsr@w3.org </a> * @author Andy Quick <a href="mailto:ac.quick@sympatico.ca">ac.quick@sympatico.ca </a> (translation to Java) * @author Fabrizio Giustina * @version $Revision: 921 $ ($Author: aditsu $) */ public final class Report { /** * used to point to Web Accessibility Guidelines. */ public static final String ACCESS_URL = "http://www.w3.org/WAI/GL"; /** * Release date String. */ public static final String RELEASE_DATE_STRING = readReleaseDate(); private static String readReleaseDate() { final Properties p = new Properties(); try { final InputStream s = Report.class.getResourceAsStream("/jtidy.properties"); p.load(s); s.close(); } catch (Exception e) { throw new RuntimeException("Failed to load jtidy.properties", e); } return p.getProperty("date"); } /** * invalid entity: missing semicolon. */ public static final short MISSING_SEMICOLON = 1; /** * invalid entity: missing semicolon. */ public static final short MISSING_SEMICOLON_NCR = 2; /** * invalid entity: unknown entity. */ public static final short UNKNOWN_ENTITY = 3; /** * invalid entity: unescaped ampersand. */ public static final short UNESCAPED_AMPERSAND = 4; /** * invalid entity: apos undefined in current definition. */ public static final short APOS_UNDEFINED = 5; /** * missing an end tag. */ public static final short MISSING_ENDTAG_FOR = 6; /** * missing end tag before. */ public static final short MISSING_ENDTAG_BEFORE = 7; /** * discarding unexpected element. */ public static final short DISCARDING_UNEXPECTED = 8; /** * nested emphasis. */ public static final short NESTED_EMPHASIS = 9; /** * non matching end tag. */ public static final short NON_MATCHING_ENDTAG = 10; /** * tag not allowed in. */ public static final short TAG_NOT_ALLOWED_IN = 11; /** * missing start tag. */ public static final short MISSING_STARTTAG = 12; /** * unexpected end tag. */ public static final short UNEXPECTED_ENDTAG = 13; /** * unsing br in place of. */ public static final short USING_BR_INPLACE_OF = 14; /** * inserting tag. */ public static final short INSERTING_TAG = 15; /** * suspected missing quote. */ public static final short SUSPECTED_MISSING_QUOTE = 16; /** * missing title element. */ public static final short MISSING_TITLE_ELEMENT = 17; /** * duplicate frameset. */ public static final short DUPLICATE_FRAMESET = 18; /** * elments can be nested. */ public static final short CANT_BE_NESTED = 19; /** * obsolete element. */ public static final short OBSOLETE_ELEMENT = 20; /** * proprietary element. */ public static final short PROPRIETARY_ELEMENT = 21; /** * unknown element. */ public static final short UNKNOWN_ELEMENT = 22; /** * trim empty element. */ public static final short TRIM_EMPTY_ELEMENT = 23; /** * coerce to end tag. */ public static final short COERCE_TO_ENDTAG = 24; /** * illegal nesting. */ public static final short ILLEGAL_NESTING = 25; /** * noframes content. */ public static final short NOFRAMES_CONTENT = 26; /** * content after body. */ public static final short CONTENT_AFTER_BODY = 27; /** * inconsistent version. */ public static final short INCONSISTENT_VERSION = 28; /** * malformed comment. */ public static final short MALFORMED_COMMENT = 29; /** * bad coment chars. */ public static final short BAD_COMMENT_CHARS = 30; /** * bad xml comment. */ public static final short BAD_XML_COMMENT = 31; /** * bad cdata comment. */ public static final short BAD_CDATA_CONTENT = 32; /** * inconsistent namespace. */ public static final short INCONSISTENT_NAMESPACE = 33; /** * doctype after tags. */ public static final short DOCTYPE_AFTER_TAGS = 34; /** * malformed doctype. */ public static final short MALFORMED_DOCTYPE = 35; /** * unexpected end of file. */ public static final short UNEXPECTED_END_OF_FILE = 36; /** * doctype not upper case. */ public static final short DTYPE_NOT_UPPER_CASE = 37; /** * too many element. */ public static final short TOO_MANY_ELEMENTS = 38; /** * unescaped element. */ public static final short UNESCAPED_ELEMENT = 39; /** * nested quotation. */ public static final short NESTED_QUOTATION = 40; /** * element not empty. */ public static final short ELEMENT_NOT_EMPTY = 41; /** * encoding IO conflict. */ public static final short ENCODING_IO_CONFLICT = 42; /** * mixed content in block. */ public static final short MIXED_CONTENT_IN_BLOCK = 43; /** * missing doctype. */ public static final short MISSING_DOCTYPE = 44; /** * space preceding xml declaration. */ public static final short SPACE_PRECEDING_XMLDECL = 45; /** * too many elements in. */ public static final short TOO_MANY_ELEMENTS_IN = 46; /** * unexpected endag in. */ public static final short UNEXPECTED_ENDTAG_IN = 47; /** * replacing element. */ public static final short REPLACING_ELEMENT = 83; /** * replacing unexcaped element. */ public static final short REPLACING_UNEX_ELEMENT = 84; /** * coerce to endtag. */ public static final short COERCE_TO_ENDTAG_WARN = 85; /** * attribute: unknown attribute. */ public static final short UNKNOWN_ATTRIBUTE = 48; /** * attribute: missing attribute. */ public static final short MISSING_ATTRIBUTE = 49; /** * attribute: missing attribute value. */ public static final short MISSING_ATTR_VALUE = 50; /** * attribute: bad attribute value. */ public static final short BAD_ATTRIBUTE_VALUE = 51; /** * attribute: unexpected gt. */ public static final short UNEXPECTED_GT = 52; /** * attribute: proprietary attribute. */ public static final short PROPRIETARY_ATTRIBUTE = 53; /** * attribute: proprietary attribute value. */ public static final short PROPRIETARY_ATTR_VALUE = 54; /** * attribute: repeated attribute. */ public static final short REPEATED_ATTRIBUTE = 55; /** * attribute: missing image map. */ public static final short MISSING_IMAGEMAP = 56; /** * attribute: xml attribute value. */ public static final short XML_ATTRIBUTE_VALUE = 57; /** * attribute: missing quotemark. */ public static final short MISSING_QUOTEMARK = 58; /** * attribute: unexpected quotemark. */ public static final short UNEXPECTED_QUOTEMARK = 59; /** * attribute: id and name mismatch. */ public static final short ID_NAME_MISMATCH = 60; /** * attribute: backslash in URI. */ public static final short BACKSLASH_IN_URI = 61; /** * attribute: fixed backslash. */ public static final short FIXED_BACKSLASH = 62; /** * attribute: illegal URI reference. */ public static final short ILLEGAL_URI_REFERENCE = 63; /** * attribute: escaped illegal URI. */ public static final short ESCAPED_ILLEGAL_URI = 64; /** * attribute: newline in URI. */ public static final short NEWLINE_IN_URI = 65; /** * attribute: anchor not unique. */ public static final short ANCHOR_NOT_UNIQUE = 66; /** * attribute: entity in id. */ public static final short ENTITY_IN_ID = 67; /** * attribute: joining attribute. */ public static final short JOINING_ATTRIBUTE = 68; /** * attribute: expected equalsign. */ public static final short UNEXPECTED_EQUALSIGN = 69; /** * attribute: attribute value not lower case. */ public static final short ATTR_VALUE_NOT_LCASE = 70; /** * attribute: id sintax. */ public static final short XML_ID_SYNTAX = 71; /** * attribute: invalid attribute. */ public static final short INVALID_ATTRIBUTE = 72; /** * attribute: bad attribute value replaced. */ public static final short BAD_ATTRIBUTE_VALUE_REPLACED = 73; /** * attribute: invalid xml id. */ public static final short INVALID_XML_ID = 74; /** * attribute: unexpected end of file. */ public static final short UNEXPECTED_END_OF_FILE_ATTR = 75; /** * character encoding: vendor specific chars. */ public static final short VENDOR_SPECIFIC_CHARS = 76; /** * character encoding: invalid sgml chars. */ public static final short INVALID_SGML_CHARS = 77; /** * character encoding: invalid utf8. */ public static final short INVALID_UTF8 = 78; /** * character encoding: invalid utf16. */ public static final short INVALID_UTF16 = 79; /** * character encoding: encoding mismatch. */ public static final short ENCODING_MISMATCH = 80; /** * character encoding: nvalid URI. */ public static final short INVALID_URI = 81; /** * character encoding: invalid NCR. */ public static final short INVALID_NCR = 82; /** * Constant used for reporting of given doctype. */ public static final short DOCTYPE_GIVEN_SUMMARY = 110; /** * Constant used for reporting of version summary. */ public static final short REPORT_VERSION_SUMMARY = 111; /** * Constant used for reporting of bad access summary. */ public static final short BADACCESS_SUMMARY = 112; /** * Constant used for reporting of bad form summary. */ public static final short BADFORM_SUMMARY = 113; /** * accessibility flaw: missing image map. */ public static final short MISSING_IMAGE_ALT = 1; /** * accessibility flaw: missing link alt. */ public static final short MISSING_LINK_ALT = 2; /** * accessibility flaw: missing summary. */ public static final short MISSING_SUMMARY = 4; /** * accessibility flaw: missing image map. */ public static final short MISSING_IMAGE_MAP = 8; /** * accessibility flaw: using frames. */ public static final short USING_FRAMES = 16; /** * accessibility flaw: using noframes. */ public static final short USING_NOFRAMES = 32; /** * presentation flaw: using spacer. */ public static final short USING_SPACER = 1; /** * presentation flaw: using layer. */ public static final short USING_LAYER = 2; /** * presentation flaw: using nobr. */ public static final short USING_NOBR = 4; /** * presentation flaw: using font. */ public static final short USING_FONT = 8; /** * presentation flaw: using body. */ public static final short USING_BODY = 16; /** * character encoding error: windows chars. */ public static final short WINDOWS_CHARS = 1; /** * character encoding error: non ascii. */ public static final short NON_ASCII = 2; /** * character encoding error: found utf16. */ public static final short FOUND_UTF16 = 4; /** * char has been replaced. */ public static final short REPLACED_CHAR = 0; /** * char has been discarder. */ public static final short DISCARDED_CHAR = 1; /** * Resource bundle with messages. */ private static ResourceBundle res; /** * Printed in GNU Emacs messages. */ private String currentFile; /** * message listener for error reporting. */ private TidyMessageListener listener; static { try { res = ResourceBundle.getBundle("org/w3c/tidy/TidyMessages"); } catch (MissingResourceException e) { throw new Error(e.toString()); } } /** * Instantiated only in Tidy() constructor. */ protected Report() { super(); } /** * Generates a complete message for the warning/error. The message is composed by: * <ul> * <li>position in file</li> * <li>prefix for the error level (warning: | error:)</li> * <li>message read from ResourceBundle</li> * <li>optional parameters added to message using MessageFormat</li> * </ul> * @param errorCode tidy error code * @param lexer Lexer * @param message key for the ResourceBundle * @param params optional parameters added with MessageFormat * @param level message level. One of <code>TidyMessage.LEVEL_ERROR</code>, * <code>TidyMessage.LEVEL_WARNING</code>,<code>TidyMessage.LEVEL_INFO</code> * @return formatted message * @throws MissingResourceException if <code>message</code> key is not available in jtidy resource bundle. * @see TidyMessage */ protected String getMessage(int errorCode, Lexer lexer, String message, Object[] params, Level level) throws MissingResourceException { String resource; resource = res.getString(message); String position; if (lexer != null && level != Level.SUMMARY) { position = getPosition(lexer); } else { position = ""; } String prefix; if (level == Level.ERROR) { prefix = res.getString("error"); } else if (level == Level.WARNING) { prefix = res.getString("warning"); } else { prefix = ""; } String messageString; if (params != null) { messageString = MessageFormat.format(resource, params); } else { messageString = resource; } if (listener != null) { TidyMessage msg = new TidyMessage(errorCode, (lexer != null) ? lexer.lines : 0, (lexer != null) ? lexer.columns : 0, level, messageString); listener.messageReceived(msg); } return position + prefix + messageString; } /** * Prints a message to lexer.errout after calling getMessage(). * @param errorCode tidy error code * @param lexer Lexer * @param message key for the ResourceBundle * @param params optional parameters added with MessageFormat * @param level message level. One of <code>TidyMessage.LEVEL_ERROR</code>, * <code>TidyMessage.LEVEL_WARNING</code>,<code>TidyMessage.LEVEL_INFO</code> * @see TidyMessage */ private void printMessage(int errorCode, Lexer lexer, String message, Object[] params, Level level) { String resource; try { resource = getMessage(errorCode, lexer, message, params, level); } catch (MissingResourceException e) { lexer.errout.println(e.toString()); return; } lexer.errout.println(resource); } /** * Prints a message to errout after calling getMessage(). Used when lexer is not yet defined. * @param errout PrintWriter * @param message key for the ResourceBundle * @param params optional parameters added with MessageFormat * @param level message level. One of <code>TidyMessage.LEVEL_ERROR</code>, * <code>TidyMessage.LEVEL_WARNING</code>,<code>TidyMessage.LEVEL_INFO</code> * @see TidyMessage */ private void printMessage(PrintWriter errout, String message, Object[] params, Level level) { String resource; try { resource = getMessage(-1, null, message, params, level); } catch (MissingResourceException e) { errout.println(e.toString()); return; } errout.println(resource); } /** * print version information. * @param p printWriter */ public void showVersion(PrintWriter p) { printMessage(p, "version_summary", new Object[]{RELEASE_DATE_STRING}, Level.SUMMARY); } /** * Returns a formatted tag name handling start and ent tags, nulls, doctypes, and text. * @param tag Node * @return formatted tag name */ private String getTagName(Node tag) { if (tag != null) { if (tag.type == Node.START_TAG) { return "<" + tag.element + ">"; } else if (tag.type == Node.END_TAG) { return "</" + tag.element + ">"; } else if (tag.type == Node.DOCTYPE_TAG) { return "<!DOCTYPE>"; } else if (tag.type == Node.TEXT_NODE) { return "plain text"; } else { return tag.element; } } return ""; } /** * Prints an "unknown option" error message. Lexer is not defined when this is called. * @param option unknown option name */ public void unknownOption(String option) { try { System.err.println(MessageFormat.format(res.getString("unknown_option"), new Object[]{option})); } catch (MissingResourceException e) { System.err.println(e.toString()); } } /** * Prints a "bad argument" error message. Lexer is not defined when this is called. * @param key argument name * @param value bad argument value */ public void badArgument(String key, String value) { try { System.err.println(MessageFormat.format(res.getString("bad_argument"), new Object[]{value, key})); } catch (MissingResourceException e) { System.err.println(e.toString()); } } /** * Returns a formatted String describing the current position in file. * @param lexer Lexer * @return String position ("line:column") */ private String getPosition(Lexer lexer) { try { // Change formatting to be parsable by GNU Emacs if (lexer.configuration.emacs) { return MessageFormat.format(res.getString("emacs_format"), new Object[]{ this.currentFile, new Integer(lexer.lines), new Integer(lexer.columns)}) + " "; } // traditional format return MessageFormat.format(res.getString("line_column"), new Object[]{ new Integer(lexer.lines), new Integer(lexer.columns)}); } catch (MissingResourceException e) { lexer.errout.println(e.toString()); } return ""; } /** * Prints encoding error messages. * @param lexer Lexer * @param code error code * @param c invalid char */ public void encodingError(Lexer lexer, int code, int c) { lexer.warnings++; if (lexer.errors > lexer.configuration.showErrors) // keep quiet after <showErrors> errors { return; } if (lexer.configuration.showWarnings) { String buf = Integer.toHexString(c); // An encoding mismatch is currently treated as a non-fatal error if ((code & ~DISCARDED_CHAR) == ENCODING_MISMATCH) { // actual encoding passed in "c" lexer.badChars |= ENCODING_MISMATCH; printMessage( code, lexer, "encoding_mismatch", new Object[]{ lexer.configuration.getInCharEncodingName(), ParsePropertyImpl.CHAR_ENCODING.getFriendlyName(null, new Integer(c), lexer.configuration)}, Level.WARNING); } else if ((code & ~DISCARDED_CHAR) == VENDOR_SPECIFIC_CHARS) { lexer.badChars |= VENDOR_SPECIFIC_CHARS; printMessage( code, lexer, "invalid_char", new Object[]{new Integer(code & DISCARDED_CHAR), buf}, Level.WARNING); } else if ((code & ~DISCARDED_CHAR) == INVALID_SGML_CHARS) { lexer.badChars |= INVALID_SGML_CHARS; printMessage( code, lexer, "invalid_char", new Object[]{new Integer(code & DISCARDED_CHAR), buf}, Level.WARNING); } else if ((code & ~DISCARDED_CHAR) == INVALID_UTF8) { lexer.badChars |= INVALID_UTF8; printMessage( code, lexer, "invalid_utf8", new Object[]{new Integer(code & DISCARDED_CHAR), buf}, Level.WARNING); } else if ((code & ~DISCARDED_CHAR) == INVALID_UTF16) { lexer.badChars |= INVALID_UTF16; printMessage( code, lexer, "invalid_utf16", new Object[]{new Integer(code & DISCARDED_CHAR), buf}, Level.WARNING); } else if ((code & ~DISCARDED_CHAR) == INVALID_NCR) { lexer.badChars |= INVALID_NCR; printMessage( code, lexer, "invalid_ncr", new Object[]{new Integer(code & DISCARDED_CHAR), buf}, Level.WARNING); } } } /** * Prints entity error messages. * @param lexer Lexer * @param code error code * @param entity invalid entity String * @param c invalid char */ public void entityError(Lexer lexer, short code, String entity, int c) { lexer.warnings++; if (lexer.errors > lexer.configuration.showErrors) // keep quiet after <showErrors> errors { return; } if (lexer.configuration.showWarnings) { switch (code) { case MISSING_SEMICOLON : printMessage(code, lexer, "missing_semicolon", new Object[]{entity}, Level.WARNING); break; case MISSING_SEMICOLON_NCR : printMessage(code, lexer, "missing_semicolon_ncr", new Object[]{entity}, Level.WARNING); break; case UNKNOWN_ENTITY : printMessage(code, lexer, "unknown_entity", new Object[]{entity}, Level.WARNING); break; case UNESCAPED_AMPERSAND : printMessage(code, lexer, "unescaped_ampersand", null, Level.WARNING); break; case APOS_UNDEFINED : printMessage(code, lexer, "apos_undefined", null, Level.WARNING); break; default : // should not reach here break; } } } /** * Prints error messages for attributes. * @param lexer Lexer * @param node current tag * @param attribute attribute * @param code error code */ public void attrError(Lexer lexer, Node node, AttVal attribute, short code) { if (code == UNEXPECTED_GT) { lexer.errors++; } else { lexer.warnings++; } if (lexer.errors > lexer.configuration.showErrors) // keep quiet after <showErrors> errors { return; } if (code == UNEXPECTED_GT) // error { printMessage(code, lexer, "unexpected_gt", new Object[]{getTagName(node)}, Level.ERROR); } if (!lexer.configuration.showWarnings) // warnings { return; } switch (code) { case UNKNOWN_ATTRIBUTE : printMessage(code, lexer, "unknown_attribute", new Object[]{attribute.attribute}, Level.WARNING); break; case MISSING_ATTRIBUTE : printMessage( code, lexer, "missing_attribute", new Object[]{getTagName(node), attribute.attribute}, Level.WARNING); break; case MISSING_ATTR_VALUE : printMessage( code, lexer, "missing_attr_value", new Object[]{getTagName(node), attribute.attribute}, Level.WARNING); break; case MISSING_IMAGEMAP : printMessage(code, lexer, "missing_imagemap", new Object[]{getTagName(node)}, Level.WARNING); lexer.badAccess |= MISSING_IMAGE_MAP; break; case BAD_ATTRIBUTE_VALUE : printMessage(code, lexer, "bad_attribute_value", new Object[]{ getTagName(node), attribute.attribute, attribute.value}, Level.WARNING); break; case XML_ID_SYNTAX : printMessage( code, lexer, "xml_id_sintax", new Object[]{getTagName(node), attribute.attribute}, Level.WARNING); break; case XML_ATTRIBUTE_VALUE : printMessage( code, lexer, "xml_attribute_value", new Object[]{getTagName(node), attribute.attribute}, Level.WARNING); break; case UNEXPECTED_QUOTEMARK : printMessage(code, lexer, "unexpected_quotemark", new Object[]{getTagName(node)}, Level.WARNING); break; case MISSING_QUOTEMARK : printMessage(code, lexer, "missing_quotemark", new Object[]{getTagName(node)}, Level.WARNING); break; case REPEATED_ATTRIBUTE : printMessage(code, lexer, "repeated_attribute", new Object[]{ getTagName(node), attribute.value, attribute.attribute}, Level.WARNING); break; case PROPRIETARY_ATTR_VALUE : printMessage( code, lexer, "proprietary_attr_value", new Object[]{getTagName(node), attribute.value}, Level.WARNING); break; case PROPRIETARY_ATTRIBUTE : printMessage( code, lexer, "proprietary_attribute", new Object[]{getTagName(node), attribute.attribute}, Level.WARNING); break; case UNEXPECTED_END_OF_FILE : // on end of file adjust reported position to end of input lexer.lines = lexer.in.getCurline(); lexer.columns = lexer.in.getCurcol(); printMessage(code, lexer, "unexpected_end_of_file", new Object[]{getTagName(node)}, Level.WARNING); break; case ID_NAME_MISMATCH : printMessage(code, lexer, "id_name_mismatch", new Object[]{getTagName(node)}, Level.WARNING); break; case BACKSLASH_IN_URI : printMessage(code, lexer, "backslash_in_uri", new Object[]{getTagName(node)}, Level.WARNING); break; case FIXED_BACKSLASH : printMessage(code, lexer, "fixed_backslash", new Object[]{getTagName(node)}, Level.WARNING); break; case ILLEGAL_URI_REFERENCE : printMessage(code, lexer, "illegal_uri_reference", new Object[]{getTagName(node)}, Level.WARNING); break; case ESCAPED_ILLEGAL_URI : printMessage(code, lexer, "escaped_illegal_uri", new Object[]{getTagName(node)}, Level.WARNING); break; case NEWLINE_IN_URI : printMessage(code, lexer, "newline_in_uri", new Object[]{getTagName(node)}, Level.WARNING); break; case ANCHOR_NOT_UNIQUE : printMessage( code, lexer, "anchor_not_unique", new Object[]{getTagName(node), attribute.value}, Level.WARNING); break; case ENTITY_IN_ID : printMessage(code, lexer, "entity_in_id", null, Level.WARNING); break; case JOINING_ATTRIBUTE : printMessage( code, lexer, "joining_attribute", new Object[]{getTagName(node), attribute.attribute}, Level.WARNING); break; case UNEXPECTED_EQUALSIGN : printMessage(code, lexer, "expected_equalsign", new Object[]{getTagName(node)}, Level.WARNING); break; case ATTR_VALUE_NOT_LCASE : printMessage(code, lexer, "attr_value_not_lcase", new Object[]{ getTagName(node), attribute.value, attribute.attribute}, Level.WARNING); break; default : break; } } /** * Prints warnings. * @param lexer Lexer * @param element parent/missing tag * @param node current tag * @param code error code */ public void warning(Lexer lexer, Node element, Node node, short code) { TagTable tt = lexer.configuration.tt; if (!((code == DISCARDING_UNEXPECTED) && lexer.badForm != 0)) // lexer->errors++; already done in BadForm() { lexer.warnings++; } // keep quiet after <showErrors> errors if (lexer.errors > lexer.configuration.showErrors) { return; } if (lexer.configuration.showWarnings) { switch (code) { case MISSING_ENDTAG_FOR : printMessage(code, lexer, "missing_endtag_for", new Object[]{element.element}, Level.WARNING); break; case MISSING_ENDTAG_BEFORE : printMessage( code, lexer, "missing_endtag_before", new Object[]{element.element, getTagName(node)}, Level.WARNING); break; case DISCARDING_UNEXPECTED : if (lexer.badForm == 0) { // the case for when this is an error not a warning, is handled later printMessage( code, lexer, "discarding_unexpected", new Object[]{getTagName(node)}, Level.WARNING); } break; case NESTED_EMPHASIS : printMessage(code, lexer, "nested_emphasis", new Object[]{getTagName(node)}, Level.INFO); break; case COERCE_TO_ENDTAG : printMessage(code, lexer, "coerce_to_endtag", new Object[]{element.element}, Level.INFO); break; case NON_MATCHING_ENDTAG : printMessage( code, lexer, "non_matching_endtag", new Object[]{getTagName(node), element.element}, Level.WARNING); break; case TAG_NOT_ALLOWED_IN : printMessage( code, lexer, "tag_not_allowed_in", new Object[]{getTagName(node), element.element}, Level.WARNING); break; case DOCTYPE_AFTER_TAGS : printMessage(code, lexer, "doctype_after_tags", null, Level.WARNING); break; case MISSING_STARTTAG : printMessage(code, lexer, "missing_starttag", new Object[]{node.element}, Level.WARNING); break; case UNEXPECTED_ENDTAG : if (element != null) { printMessage( code, lexer, "unexpected_endtag_in", new Object[]{node.element, element.element}, Level.WARNING); } else { printMessage(code, lexer, "unexpected_endtag", new Object[]{node.element}, Level.WARNING); } break; case TOO_MANY_ELEMENTS : if (element != null) { printMessage( code, lexer, "too_many_elements_in", new Object[]{node.element, element.element}, Level.WARNING); } else { printMessage(code, lexer, "too_many_elements", new Object[]{node.element}, Level.WARNING); } break; case USING_BR_INPLACE_OF : printMessage(code, lexer, "using_br_inplace_of", new Object[]{getTagName(node)}, Level.WARNING); break; case INSERTING_TAG : printMessage(code, lexer, "inserting_tag", new Object[]{node.element}, Level.WARNING); break; case CANT_BE_NESTED : printMessage(code, lexer, "cant_be_nested", new Object[]{getTagName(node)}, Level.WARNING); break; case PROPRIETARY_ELEMENT : printMessage(code, lexer, "proprietary_element", new Object[]{getTagName(node)}, Level.WARNING); if (node.tag == tt.tagLayer) { lexer.badLayout |= USING_LAYER; } else if (node.tag == tt.tagSpacer) { lexer.badLayout |= USING_SPACER; } else if (node.tag == tt.tagNobr) { lexer.badLayout |= USING_NOBR; } break; case OBSOLETE_ELEMENT : if (element.tag != null && (element.tag.model & Dict.CM_OBSOLETE) != 0) { printMessage(code, lexer, "obsolete_element", new Object[]{ getTagName(element), getTagName(node)}, Level.WARNING); } else { printMessage(code, lexer, "replacing_element", new Object[]{ getTagName(element), getTagName(node)}, Level.WARNING); } break; case UNESCAPED_ELEMENT : printMessage(code, lexer, "unescaped_element", new Object[]{getTagName(element)}, Level.WARNING); break; case TRIM_EMPTY_ELEMENT : printMessage(code, lexer, "trim_empty_element", new Object[]{getTagName(element)}, Level.WARNING); break; case MISSING_TITLE_ELEMENT : printMessage(code, lexer, "missing_title_element", null, Level.WARNING); break; case ILLEGAL_NESTING : printMessage(code, lexer, "illegal_nesting", new Object[]{getTagName(element)}, Level.WARNING); break; case NOFRAMES_CONTENT : printMessage(code, lexer, "noframes_content", new Object[]{getTagName(node)}, Level.WARNING); break; case INCONSISTENT_VERSION : printMessage(code, lexer, "inconsistent_version", null, Level.WARNING); break; case MALFORMED_DOCTYPE : printMessage(code, lexer, "malformed_doctype", null, Level.WARNING); break; case CONTENT_AFTER_BODY : printMessage(code, lexer, "content_after_body", null, Level.WARNING); break; case MALFORMED_COMMENT : printMessage(code, lexer, "malformed_comment", null, Level.WARNING); break; case BAD_COMMENT_CHARS : printMessage(code, lexer, "bad_comment_chars", null, Level.WARNING); break; case BAD_XML_COMMENT : printMessage(code, lexer, "bad_xml_comment", null, Level.WARNING); break; case BAD_CDATA_CONTENT : printMessage(code, lexer, "bad_cdata_content", null, Level.WARNING); break; case INCONSISTENT_NAMESPACE : printMessage(code, lexer, "inconsistent_namespace", null, Level.WARNING); break; case DTYPE_NOT_UPPER_CASE : printMessage(code, lexer, "dtype_not_upper_case", null, Level.WARNING); break; case UNEXPECTED_END_OF_FILE : // on end of file adjust reported position to end of input lexer.lines = lexer.in.getCurline(); lexer.columns = lexer.in.getCurcol(); printMessage( code, lexer, "unexpected_end_of_file", new Object[]{getTagName(element)}, Level.WARNING); break; case NESTED_QUOTATION : printMessage(code, lexer, "nested_quotation", null, Level.WARNING); break; case ELEMENT_NOT_EMPTY : printMessage(code, lexer, "element_not_empty", new Object[]{getTagName(element)}, Level.WARNING); break; case MISSING_DOCTYPE : printMessage(code, lexer, "missing_doctype", null, Level.WARNING); break; default : break; } } if ((code == DISCARDING_UNEXPECTED) && lexer.badForm != 0) { // the case for when this is a warning not an error, is handled earlier printMessage(code, lexer, "discarding_unexpected", new Object[]{getTagName(node)}, Level.ERROR); } } /** * Prints errors. * @param lexer Lexer * @param element parent/missing tag * @param node current tag * @param code error code */ public void error(Lexer lexer, Node element, Node node, short code) { lexer.errors++; // keep quiet after <showErrors> errors if (lexer.errors > lexer.configuration.showErrors) { return; } if (code == SUSPECTED_MISSING_QUOTE) { printMessage(code, lexer, "suspected_missing_quote", null, Level.ERROR); } else if (code == DUPLICATE_FRAMESET) { printMessage(code, lexer, "duplicate_frameset", null, Level.ERROR); } else if (code == UNKNOWN_ELEMENT) { printMessage(code, lexer, "unknown_element", new Object[]{getTagName(node)}, Level.ERROR); } else if (code == UNEXPECTED_ENDTAG) { if (element != null) { printMessage( code, lexer, "unexpected_endtag_in", new Object[]{node.element, element.element}, Level.ERROR); } else { printMessage(code, lexer, "unexpected_endtag", new Object[]{node.element}, Level.ERROR); } } } /** * Prints error summary. * @param lexer Lexer */ public void errorSummary(Lexer lexer) { // adjust badAccess to that its null if frames are ok if ((lexer.badAccess & (USING_FRAMES | USING_NOFRAMES)) != 0) { if (!(((lexer.badAccess & USING_FRAMES) != 0) && ((lexer.badAccess & USING_NOFRAMES) == 0))) { lexer.badAccess &= ~(USING_FRAMES | USING_NOFRAMES); } } if (lexer.badChars != 0) { if ((lexer.badChars & VENDOR_SPECIFIC_CHARS) != 0) { int encodingChoiche = 0; if ("Cp1252".equals(lexer.configuration.getInCharEncodingName())) { encodingChoiche = 1; } else if ("MacRoman".equals(lexer.configuration.getInCharEncodingName())) { encodingChoiche = 2; } printMessage(VENDOR_SPECIFIC_CHARS, lexer, "vendor_specific_chars_summary", new Object[]{new Integer( encodingChoiche)}, Level.SUMMARY); } if ((lexer.badChars & INVALID_SGML_CHARS) != 0 || (lexer.badChars & INVALID_NCR) != 0) { int encodingChoiche = 0; if ("Cp1252".equals(lexer.configuration.getInCharEncodingName())) { encodingChoiche = 1; } else if ("MacRoman".equals(lexer.configuration.getInCharEncodingName())) { encodingChoiche = 2; } printMessage(INVALID_SGML_CHARS, lexer, "invalid_sgml_chars_summary", new Object[]{new Integer( encodingChoiche)}, Level.SUMMARY); } if ((lexer.badChars & INVALID_UTF8) != 0) { printMessage(INVALID_UTF8, lexer, "invalid_utf8_summary", null, Level.SUMMARY); } if ((lexer.badChars & INVALID_UTF16) != 0) { printMessage(INVALID_UTF16, lexer, "invalid_utf16_summary", null, Level.SUMMARY); } if ((lexer.badChars & INVALID_URI) != 0) { printMessage(INVALID_URI, lexer, "invaliduri_summary", null, Level.SUMMARY); } } if (lexer.badForm != 0) { printMessage(BADFORM_SUMMARY, lexer, "badform_summary", null, Level.SUMMARY); } if (lexer.badAccess != 0) { if ((lexer.badAccess & MISSING_SUMMARY) != 0) { printMessage(MISSING_SUMMARY, lexer, "badaccess_missing_summary", null, Level.SUMMARY); } if ((lexer.badAccess & MISSING_IMAGE_ALT) != 0) { printMessage(MISSING_IMAGE_ALT, lexer, "badaccess_missing_image_alt", null, Level.SUMMARY); } if ((lexer.badAccess & MISSING_IMAGE_MAP) != 0) { printMessage(MISSING_IMAGE_MAP, lexer, "badaccess_missing_image_map", null, Level.SUMMARY); } if ((lexer.badAccess & MISSING_LINK_ALT) != 0) { printMessage(MISSING_LINK_ALT, lexer, "badaccess_missing_link_alt", null, Level.SUMMARY); } if (((lexer.badAccess & USING_FRAMES) != 0) && ((lexer.badAccess & USING_NOFRAMES) == 0)) { printMessage(USING_FRAMES, lexer, "badaccess_frames", null, Level.SUMMARY); } printMessage(BADACCESS_SUMMARY, lexer, "badaccess_summary", new Object[]{ACCESS_URL}, Level.SUMMARY); } if (lexer.badLayout != 0) { if ((lexer.badLayout & USING_LAYER) != 0) { printMessage(USING_LAYER, lexer, "badlayout_using_layer", null, Level.SUMMARY); } if ((lexer.badLayout & USING_SPACER) != 0) { printMessage(USING_SPACER, lexer, "badlayout_using_spacer", null, Level.SUMMARY); } if ((lexer.badLayout & USING_FONT) != 0) { printMessage(USING_FONT, lexer, "badlayout_using_font", null, Level.SUMMARY); } if ((lexer.badLayout & USING_NOBR) != 0) { printMessage(USING_NOBR, lexer, "badlayout_using_nobr", null, Level.SUMMARY); } if ((lexer.badLayout & USING_BODY) != 0) { printMessage(USING_BODY, lexer, "badlayout_using_body", null, Level.SUMMARY); } } } /** * Prints the "unknown option" message. * @param errout PrintWriter * @param c invalid option char */ public void unknownOption(PrintWriter errout, char c) { printMessage(errout, "unrecognized_option", new Object[]{new String(new char[]{c})}, Level.ERROR); } /** * Prints the "unknown file" message. * @param errout PrintWriter * @param file invalid file name */ public void unknownFile(PrintWriter errout, String file) { printMessage(errout, "unknown_file", new Object[]{"Tidy", file}, Level.ERROR); } /** * Prints the "needs author intervention" message. * @param errout PrintWriter */ public void needsAuthorIntervention(PrintWriter errout) { printMessage(errout, "needs_author_intervention", null, Level.SUMMARY); } /** * Prints the "missing body" message. * @param errout PrintWriter */ public void missingBody(PrintWriter errout) { printMessage(errout, "missing_body", null, Level.ERROR); } /** * Prints the number of generated slides. * @param errout PrintWriter * @param count slides count */ public void reportNumberOfSlides(PrintWriter errout, int count) { printMessage(errout, "slides_found", new Object[]{new Integer(count)}, Level.SUMMARY); } /** * Prints tidy general info. * @param errout PrintWriter */ public void generalInfo(PrintWriter errout) { printMessage(errout, "general_info", null, Level.SUMMARY); } /** * Sets the current file name. * @param filename current file. */ public void setFilename(String filename) { this.currentFile = filename; // for use with Gnu Emacs } /** * Prints information for html version in input file. * @param errout PrintWriter * @param lexer Lexer * @param filename file name * @param doctype doctype Node */ public void reportVersion(PrintWriter errout, Lexer lexer, String filename, Node doctype) { int i, c; int state = 0; String vers = lexer.htmlVersionName(); int[] cc = new int[1]; // adjust reported position to first line lexer.lines = 1; lexer.columns = 1; if (doctype != null) { StringBuffer doctypeBuffer = new StringBuffer(); for (i = doctype.start; i < doctype.end; ++i) { c = doctype.textarray[i]; // look for UTF-8 multibyte character if (c < 0) { i += PPrint.getUTF8(doctype.textarray, i, cc); c = cc[0]; } if (c == '"') { ++state; } else if (state == 1) { doctypeBuffer.append((char) c); } } printMessage( DOCTYPE_GIVEN_SUMMARY, lexer, "doctype_given", new Object[]{filename, doctypeBuffer}, Level.SUMMARY); } printMessage(REPORT_VERSION_SUMMARY, lexer, "report_version", new Object[]{ filename, (vers != null ? vers : "HTML proprietary")}, Level.SUMMARY); } /** * Prints the number of error/warnings found. * @param errout PrintWriter * @param lexer Lexer */ public void reportNumWarnings(PrintWriter errout, Lexer lexer) { if (lexer.warnings > 0 || lexer.errors > 0) { printMessage( errout, "num_warnings", new Object[]{new Integer(lexer.warnings), new Integer(lexer.errors)}, Level.SUMMARY); } else { printMessage(errout, "no_warnings", null, Level.SUMMARY); } } /** * Prints tidy help. * @param out PrintWriter */ public void helpText(PrintWriter out) { printMessage(out, "help_text", new Object[]{"Tidy", RELEASE_DATE_STRING}, Level.SUMMARY); } /** * Prints the "bad tree" message. * @param errout PrintWriter */ public void badTree(PrintWriter errout) { printMessage(errout, "bad_tree", null, Level.ERROR); } /** * Adds a message listener. * @param listener TidyMessageListener */ public void addMessageListener(TidyMessageListener listener) { this.listener = listener; } }