001package Torello.HTML; 002 003import java.util.regex.*; 004 005/** 006 * This {@code Exception} is generated, usually, when a quote-within-quote problem has occurred 007 * inside HTML Attributes. 008 * 009 * <BR /><BR />Attribute-<B STYLE="color: red;">values</B> cannot contain quotes, unless the 010 * inner-quotes do not match the outer-quotes. Generally, there are not many HTML Inner-Tags that 011 * use quotes, other than the occasional {@code ALT="..."} text (in an image element), or possibly 012 * a Java-Script listener attribute. 013 * 014 * <BR /><BR />However, this package performs quite a bit of {@code String}-operations, so 015 * {@code String's} are checked when any method or constructor which builds instances of class 016 * {@link TagNode} containing any Inner-Tag <B STYLE="color: red;">Key-Value Pairs</B>. 017 * 018 * <BR /><BR />In addition to checking for double-within-double-quotation mark problems (or 019 * single-quote inside of a singly-quoted string), this {@code Exception} is also thrown if a user 020 * attempts to assign an attribute <B STYLE="color: red;">value</B> that uses the 021 * 'no-quotation-marks' version of attribute-<B STYLE="color: red;">value</B> pairs <I>when the 022 * value he is passing has any white-space, inside the 023 * <B STYLE="color: red;">value</B>-{@code String} at all.</I> 024 */ 025public class QuotesException extends IllegalArgumentException 026{ 027 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDEX> */ 028 public static final long serialVersionUID = 1; 029 030 /** Constructs a {@code QuotesException} with no detail message. */ 031 public QuotesException() 032 { super(); } 033 034 /** 035 * Constructs a {@code QuotesException} with the specified detail message. 036 * @param message the detail message. 037 */ 038 public QuotesException(String message) 039 { super(message); } 040 041 /** 042 * Constructs a new exception with the specified detail message and cause. 043 * 044 * <BR /><BR /><B CLASS=JDDescLabel>NOTE:</B> 045 * 046 * <BR /><BR />The detail message associated with cause is not automatically incorporated into 047 * this exception's detail message. 048 * 049 * @param message The detail message (which is saved for later retrieval by the 050 * {@code Throwable.getMessage()} method). 051 * 052 * @param cause the cause (which is saved for later retrieval by the 053 * {@code Throwable.getCause()} method). (A null value is permitted, and indicates that the 054 * cause is nonexistent or unknown.) 055 */ 056 public QuotesException(String message, Throwable cause) 057 { super(message, cause); } 058 059 /** 060 * Constructs a new exception with the specified cause and a detail message of 061 * {@code (cause==null ? null : cause.toString())} (which typically contains the class and 062 * detail message of cause). This constructor is useful for exceptions that are little more 063 * than wrappers for other throwables. 064 * 065 * @param cause the cause (which is saved for later retrieval by the 066 * {@code Throwable.getCause()} method). (A null value is permitted, and indicates that the 067 * cause is nonexistent or unknown.) 068 */ 069 public QuotesException(Throwable cause) 070 { super(cause); } 071 072 /** 073 * This Regular-Expression {@code Pattern} is used internally for one particular scenario 074 * involving a null quotes specifier. It states that a {@code String} must conform to either 075 * single-quotes, double-quotes or no-quotes. 076 * 077 * <DIV CLASS="LOC">{@code 078 * // Throws Exception - No surrounding-quotes, has spaces 079 * check("This is an Attribute Value", null, "No Message"); 080 * 081 * // Passes Inspection - No surrounding-quotes, but has no spaces. 082 * check("This-is-an-Attribute-Value", null, "No Message"); 083 * 084 * // Throws Exception - Has surrounding-quotes, but has quote-within-quote 085 * check("This is an\"Attribute\" Value", null, "No Message"); 086 * 087 * // Passes Inspection - Has surrounding-quotes, no quote-within-quote 088 * check("'This is an attribute value'", null, "No Message"); 089 * }</DIV> 090 */ 091 protected static final Pattern QUOTES_CHECKER = 092 Pattern.compile("^(\"[^\"]*\"|'[^']*'|[^'\"\\s]*)$"); 093 094 /** 095 * The primary purpose of this {@code static} function is to generate a uniformly formatted 096 * error message when a "Quote within Quote" problem is identified. If parameter 097 * {@code 'quotes'} is set to {@code SD.SingleQuotes}, then finding a single-quote within the 098 * input {@code String} will cause this {@code Exception} throw. If quotes is set to 099 * {@code SD.DoubleQuotes}, then finding a double-quote in the input {@code String} will cause 100 * this {@code Exception} throw. If parameter {@code 'quotes'} is null, then finding either 101 * will generate a {@code QuotesException}. 102 * 103 * @param s The {@code String}-token to check 104 * 105 * @param quotes The surrounding quotes used, or null if no quotes are being used. If this 106 * value is null, then finding either quote in the {@code 's'} parameter will cause this 107 * {@code QuotesException} throw. 108 * 109 * @param message A brief error message to report to the programmer. If this is null, then it 110 * is not included. 111 * 112 * @throws QuotesException If there is a "Quote within Quote" problem identified, as explained 113 * above. 114 */ 115 public static void check(String s, SD quotes, String message) 116 { 117 if (quotes == null) 118 { 119 if (! QUOTES_CHECKER.matcher(s).find()) throw new QuotesException( 120 ((message == null) 121 ? "" 122 : (message.endsWith("\n") ? message : (message + "\n"))) + 123 "\nString: [" + s + "]\nis not being properly quoted." 124 ); 125 } 126 127 else if (s.indexOf(quotes.quote) != -1) throw new QuotesException( 128 ((message == null) 129 ? "" 130 : (message.endsWith("\n") ? message : (message + "\n"))) + 131 "\nString: [" + s + "]\n" + 132 "contains a quote that matches the surrounding quotes: " + quotes.quote 133 ); 134 } 135}