1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package Torello.HTML;

import java.util.regex.*;

/**
 * This {@code Exception} is generated, usually, when a quote-within-quote problem has occurred
 * inside HTML Attributes.
 *   
 * <BR /><BR />Attribute-<B STYLE="color: red;">values</B> cannot contain quotes, unless the
 * inner-quotes do not match the outer-quotes.  Generally, there are not many HTML Inner-Tags that
 * use quotes, other than the occasional {@code ALT="..."} text (in an image element), or possibly
 * a Java-Script listener attribute.
 * 
 * <BR /><BR />However, this package performs quite a bit of {@code String}-operations, so 
 * {@code String's} are checked when any method or constructor which builds instances of class
 * {@link TagNode} containing any Inner-Tag <B STYLE="color: red;">Key-Value Pairs</B>.
 * 
 * <BR /><BR />In addition to checking for double-within-double-quotation mark problems (or 
 * single-quote inside of a singly-quoted string), this {@code Exception} is also thrown if a user
 * attempts to assign an attribute <B STYLE="color: red;">value</B> that uses the
 * 'no-quotation-marks' version of attribute-<B STYLE="color: red;">value</B> pairs <I>when the
 * value he is passing has any white-space, inside the
 * <B STYLE="color: red;">value</B>-{@code String} at all.</I>
 */
public class QuotesException extends IllegalArgumentException
{
    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDEX> */
    public static final long serialVersionUID = 1;

    /** Constructs a {@code QuotesException} with no detail message. */
    public QuotesException()
    { super(); }

    /**
     * Constructs a {@code QuotesException} with the specified detail message.
     * @param message the detail message.
     */
    public QuotesException(String message)
    { super(message); }

    /**
     * Constructs a new exception with the specified detail message and cause.
     * 
     * <BR /><BR /><B CLASS=JDDescLabel>NOTE:</B>
     * 
     * <BR /><BR />The detail message associated with cause is not automatically incorporated into
     * this exception's detail message.
     * 
     * @param message The detail message (which is saved for later retrieval by the
     * {@code Throwable.getMessage()} method).
     * 
     * @param cause the cause (which is saved for later retrieval by the
     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
     * cause is nonexistent or unknown.)
     */
    public QuotesException(String message, Throwable cause)
    { super(message, cause); }

    /**
     * Constructs a new exception with the specified cause and a detail message of
     * {@code (cause==null ? null : cause.toString())} (which typically contains the class and
     * detail message of cause).  This constructor is useful for exceptions that are little more
     * than wrappers for other throwables.
     * 
     * @param cause the cause (which is saved for later retrieval by the
     * {@code Throwable.getCause()} method).  (A null value is permitted, and indicates that the
     * cause is nonexistent or unknown.)
     */
    public QuotesException(Throwable cause)
    { super(cause); }

    /**
     * This Regular-Expression {@code Pattern} is used internally for one particular scenario 
     * involving a null quotes specifier.  It states that a {@code String} must conform to either
     * single-quotes, double-quotes or no-quotes.
     *
     * <DIV CLASS="LOC">{@code
     * // Throws Exception - No surrounding-quotes, has spaces
     * check("This is an Attribute Value", null, "No Message");
     *
     * // Passes Inspection - No surrounding-quotes, but has no spaces.
     * check("This-is-an-Attribute-Value", null, "No Message");
     * 
     * // Throws Exception - Has surrounding-quotes, but has quote-within-quote
     * check("This is an\"Attribute\" Value", null, "No Message");
     * 
     * // Passes Inspection - Has surrounding-quotes, no quote-within-quote
     * check("'This is an attribute value'", null, "No Message");
     * }</DIV>
     */
    protected static final Pattern QUOTES_CHECKER =
        Pattern.compile("^(\"[^\"]*\"|'[^']*'|[^'\"\\s]*)$");

    /**
     * The primary purpose of this {@code static} function is to generate a uniformly formatted
     * error message when a "Quote within Quote" problem is identified.  If parameter
     * {@code 'quotes'} is set to {@code SD.SingleQuotes}, then finding a single-quote within the
     * input {@code String} will cause this {@code Exception} throw.  If quotes is set to
     * {@code SD.DoubleQuotes}, then finding a double-quote in the input {@code String} will cause
     * this {@code Exception} throw.  If parameter {@code 'quotes'} is null, then finding either
     * will generate a {@code QuotesException}.
     * 
     * @param s The {@code String}-token to check
     * 
     * @param quotes The surrounding quotes used, or null if no quotes are being used.  If this
     * value is null, then finding either quote in the {@code 's'} parameter will cause this
     * {@code QuotesException} throw.
     * 
     * @param message A brief error message to report to the programmer.  If this is null, then it
     * is not included.
     * 
     * @throws QuotesException If there is a "Quote within Quote" problem identified, as explained
     * above.
     */
    public static void check(String s, SD quotes, String message)
    {
        if (quotes == null)
        {
            if (! QUOTES_CHECKER.matcher(s).find()) throw new QuotesException(
                ((message == null)
                    ? ""
                    : (message.endsWith("\n") ? message : (message + "\n"))) +
                "\nString: [" + s + "]\nis not being properly quoted."
            );
        }

        else if (s.indexOf(quotes.quote) != -1) throw new QuotesException(
            ((message == null)
                ? ""
                : (message.endsWith("\n") ? message : (message + "\n"))) +
            "\nString: [" + s + "]\n" +
            "contains a quote that matches the surrounding quotes: " + quotes.quote
        );
    }
}