View Javadoc
1   package org.argeo.cms.ui.forms;
2   
3   import java.io.StringReader;
4   import java.text.MessageFormat;
5   import java.util.Arrays;
6   import java.util.HashMap;
7   import java.util.List;
8   import java.util.Map;
9   
10  import javax.xml.parsers.SAXParser;
11  import javax.xml.parsers.SAXParserFactory;
12  
13  import org.eclipse.rap.rwt.SingletonUtil;
14  import org.eclipse.swt.widgets.Widget;
15  import org.xml.sax.Attributes;
16  import org.xml.sax.InputSource;
17  import org.xml.sax.helpers.DefaultHandler;
18  
19  /**
20   * Copy of RAP v2.3 since it is in an internal package.
21   */
22  class MarkupValidatorCopy {
23  
24  	// Used by Eclipse Scout project
25  	public static final String MARKUP_VALIDATION_DISABLED = "org.eclipse.rap.rwt.markupValidationDisabled";
26  
27  	private static final String DTD = createDTD();
28  	private static final Map<String, String[]> SUPPORTED_ELEMENTS = createSupportedElementsMap();
29  	private final SAXParser saxParser;
30  
31  	public static MarkupValidatorCopy getInstance() {
32  		return SingletonUtil.getSessionInstance(MarkupValidatorCopy.class);
33  	}
34  
35  	public MarkupValidatorCopy() {
36  		saxParser = createSAXParser();
37  	}
38  
39  	public void validate(String text) {
40  		StringBuilder markup = new StringBuilder();
41  		markup.append(DTD);
42  		markup.append("<html>");
43  		markup.append(text);
44  		markup.append("</html>");
45  		InputSource inputSource = new InputSource(new StringReader(markup.toString()));
46  		try {
47  			saxParser.parse(inputSource, new MarkupHandler());
48  		} catch (RuntimeException exception) {
49  			throw exception;
50  		} catch (Exception exception) {
51  			throw new IllegalArgumentException("Failed to parse markup text", exception);
52  		}
53  	}
54  
55  	public static boolean isValidationDisabledFor(Widget widget) {
56  		return Boolean.TRUE.equals(widget.getData(MARKUP_VALIDATION_DISABLED));
57  	}
58  
59  	private static SAXParser createSAXParser() {
60  		SAXParser result = null;
61  		SAXParserFactory parserFactory = SAXParserFactory.newInstance();
62  		try {
63  			result = parserFactory.newSAXParser();
64  		} catch (Exception exception) {
65  			throw new RuntimeException("Failed to create SAX parser", exception);
66  		}
67  		return result;
68  	}
69  
70  	private static String createDTD() {
71  		StringBuilder result = new StringBuilder();
72  		result.append("<!DOCTYPE html [");
73  		result.append("<!ENTITY quot \"&#34;\">");
74  		result.append("<!ENTITY amp \"&#38;\">");
75  		result.append("<!ENTITY apos \"&#39;\">");
76  		result.append("<!ENTITY lt \"&#60;\">");
77  		result.append("<!ENTITY gt \"&#62;\">");
78  		result.append("<!ENTITY nbsp \"&#160;\">");
79  		result.append("<!ENTITY ensp \"&#8194;\">");
80  		result.append("<!ENTITY emsp \"&#8195;\">");
81  		result.append("<!ENTITY ndash \"&#8211;\">");
82  		result.append("<!ENTITY mdash \"&#8212;\">");
83  		result.append("]>");
84  		return result.toString();
85  	}
86  
87  	private static Map<String, String[]> createSupportedElementsMap() {
88  		Map<String, String[]> result = new HashMap<String, String[]>();
89  		result.put("html", new String[0]);
90  		result.put("br", new String[0]);
91  		result.put("b", new String[] { "style" });
92  		result.put("strong", new String[] { "style" });
93  		result.put("i", new String[] { "style" });
94  		result.put("em", new String[] { "style" });
95  		result.put("sub", new String[] { "style" });
96  		result.put("sup", new String[] { "style" });
97  		result.put("big", new String[] { "style" });
98  		result.put("small", new String[] { "style" });
99  		result.put("del", new String[] { "style" });
100 		result.put("ins", new String[] { "style" });
101 		result.put("code", new String[] { "style" });
102 		result.put("samp", new String[] { "style" });
103 		result.put("kbd", new String[] { "style" });
104 		result.put("var", new String[] { "style" });
105 		result.put("cite", new String[] { "style" });
106 		result.put("dfn", new String[] { "style" });
107 		result.put("q", new String[] { "style" });
108 		result.put("abbr", new String[] { "style", "title" });
109 		result.put("span", new String[] { "style" });
110 		result.put("img", new String[] { "style", "src", "width", "height", "title", "alt" });
111 		result.put("a", new String[] { "style", "href", "target", "title" });
112 		return result;
113 	}
114 
115 	private static class MarkupHandler extends DefaultHandler {
116 
117 		@Override
118 		public void startElement(String uri, String localName, String name, Attributes attributes) {
119 			checkSupportedElements(name, attributes);
120 			checkSupportedAttributes(name, attributes);
121 			checkMandatoryAttributes(name, attributes);
122 		}
123 
124 		private static void checkSupportedElements(String elementName, Attributes attributes) {
125 			if (!SUPPORTED_ELEMENTS.containsKey(elementName)) {
126 				throw new IllegalArgumentException("Unsupported element in markup text: " + elementName);
127 			}
128 		}
129 
130 		private static void checkSupportedAttributes(String elementName, Attributes attributes) {
131 			if (attributes.getLength() > 0) {
132 				List<String> supportedAttributes = Arrays.asList(SUPPORTED_ELEMENTS.get(elementName));
133 				int index = 0;
134 				String attributeName = attributes.getQName(index);
135 				while (attributeName != null) {
136 					if (!supportedAttributes.contains(attributeName)) {
137 						String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text";
138 						message = MessageFormat.format(message, new Object[] { attributeName, elementName });
139 						throw new IllegalArgumentException(message);
140 					}
141 					index++;
142 					attributeName = attributes.getQName(index);
143 				}
144 			}
145 		}
146 
147 		private static void checkMandatoryAttributes(String elementName, Attributes attributes) {
148 			checkIntAttribute(elementName, attributes, "img", "width");
149 			checkIntAttribute(elementName, attributes, "img", "height");
150 		}
151 
152 		private static void checkIntAttribute(String elementName, Attributes attributes, String checkedElementName,
153 				String checkedAttributeName) {
154 			if (checkedElementName.equals(elementName)) {
155 				String attribute = attributes.getValue(checkedAttributeName);
156 				try {
157 					Integer.parseInt(attribute);
158 				} catch (NumberFormatException exception) {
159 					String message = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer";
160 					Object[] arguments = new Object[] { checkedAttributeName, checkedElementName };
161 					message = MessageFormat.format(message, arguments);
162 					throw new IllegalArgumentException(message);
163 				}
164 			}
165 		}
166 
167 	}
168 
169 }