+package org.argeo.cms.internal.text;
+
+import java.io.StringReader;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.rap.rwt.SingletonUtil;
+import org.eclipse.swt.widgets.Widget;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.helpers.DefaultHandler;
+
+/** Copy of RAP v2.3 since it is in an internal package. */
+class MarkupValidatorCopy {
+
+ // Used by Eclipse Scout project
+ public static final String MARKUP_VALIDATION_DISABLED
+ = "org.eclipse.rap.rwt.markupValidationDisabled";
+
+ private static final String DTD = createDTD();
+ private static final Map<String, String[]> SUPPORTED_ELEMENTS = createSupportedElementsMap();
+ private final SAXParser saxParser;
+
+ public static MarkupValidatorCopy getInstance() {
+ return SingletonUtil.getSessionInstance( MarkupValidatorCopy.class );
+ }
+
+ public MarkupValidatorCopy() {
+ saxParser = createSAXParser();
+ }
+
+ public void validate( String text ) {
+ StringBuilder markup = new StringBuilder();
+ markup.append( DTD );
+ markup.append( "<html>" );
+ markup.append( text );
+ markup.append( "</html>" );
+ InputSource inputSource = new InputSource( new StringReader( markup.toString() ) );
+ try {
+ saxParser.parse( inputSource, new MarkupHandler() );
+ } catch( RuntimeException exception ) {
+ throw exception;
+ } catch( Exception exception ) {
+ throw new IllegalArgumentException( "Failed to parse markup text", exception );
+ }
+ }
+
+ public static boolean isValidationDisabledFor( Widget widget ) {
+ return Boolean.TRUE.equals( widget.getData( MARKUP_VALIDATION_DISABLED ) );
+ }
+
+ private static SAXParser createSAXParser() {
+ SAXParser result = null;
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ try {
+ result = parserFactory.newSAXParser();
+ } catch( Exception exception ) {
+ throw new RuntimeException( "Failed to create SAX parser", exception );
+ }
+ return result;
+ }
+
+ private static String createDTD() {
+ StringBuilder result = new StringBuilder();
+ result.append( "<!DOCTYPE html [" );
+ result.append( "<!ENTITY quot \""\">" );
+ result.append( "<!ENTITY amp \"&\">" );
+ result.append( "<!ENTITY apos \"'\">" );
+ result.append( "<!ENTITY lt \"<\">" );
+ result.append( "<!ENTITY gt \">\">" );
+ result.append( "<!ENTITY nbsp \" \">" );
+ result.append( "<!ENTITY ensp \" \">" );
+ result.append( "<!ENTITY emsp \" \">" );
+ result.append( "<!ENTITY ndash \"–\">" );
+ result.append( "<!ENTITY mdash \"—\">" );
+ result.append( "]>" );
+ return result.toString();
+ }
+
+ private static Map<String, String[]> createSupportedElementsMap() {
+ Map<String, String[]> result = new HashMap<String, String[]>();
+ result.put( "html", new String[ 0 ] );
+ result.put( "br", new String[ 0 ] );
+ result.put( "b", new String[] { "style" } );
+ result.put( "strong", new String[] { "style" } );
+ result.put( "i", new String[] { "style" } );
+ result.put( "em", new String[] { "style" } );
+ result.put( "sub", new String[] { "style" } );
+ result.put( "sup", new String[] { "style" } );
+ result.put( "big", new String[] { "style" } );
+ result.put( "small", new String[] { "style" } );
+ result.put( "del", new String[] { "style" } );
+ result.put( "ins", new String[] { "style" } );
+ result.put( "code", new String[] { "style" } );
+ result.put( "samp", new String[] { "style" } );
+ result.put( "kbd", new String[] { "style" } );
+ result.put( "var", new String[] { "style" } );
+ result.put( "cite", new String[] { "style" } );
+ result.put( "dfn", new String[] { "style" } );
+ result.put( "q", new String[] { "style" } );
+ result.put( "abbr", new String[] { "style", "title" } );
+ result.put( "span", new String[] { "style" } );
+ result.put( "img", new String[] { "style", "src", "width", "height", "title", "alt" } );
+ result.put( "a", new String[] { "style", "href", "target", "title" } );
+ return result;
+ }
+
+ private static class MarkupHandler extends DefaultHandler {
+
+ @Override
+ public void startElement( String uri, String localName, String name, Attributes attributes ) {
+ checkSupportedElements( name, attributes );
+ checkSupportedAttributes( name, attributes );
+ checkMandatoryAttributes( name, attributes );
+ }
+
+ private static void checkSupportedElements( String elementName, Attributes attributes ) {
+ if( !SUPPORTED_ELEMENTS.containsKey( elementName ) ) {
+ throw new IllegalArgumentException( "Unsupported element in markup text: " + elementName );
+ }
+ }
+
+ private static void checkSupportedAttributes( String elementName, Attributes attributes ) {
+ if( attributes.getLength() > 0 ) {
+ List<String> supportedAttributes = Arrays.asList( SUPPORTED_ELEMENTS.get( elementName ) );
+ int index = 0;
+ String attributeName = attributes.getQName( index );
+ while( attributeName != null ) {
+ if( !supportedAttributes.contains( attributeName ) ) {
+ String message = "Unsupported attribute \"{0}\" for element \"{1}\" in markup text";
+ message = MessageFormat.format( message, new Object[] { attributeName, elementName } );
+ throw new IllegalArgumentException( message );
+ }
+ index++;
+ attributeName = attributes.getQName( index );
+ }
+ }
+ }
+
+ private static void checkMandatoryAttributes( String elementName, Attributes attributes ) {
+ checkIntAttribute( elementName, attributes, "img", "width" );
+ checkIntAttribute( elementName, attributes, "img", "height" );
+ }
+
+ private static void checkIntAttribute( String elementName,
+ Attributes attributes,
+ String checkedElementName,
+ String checkedAttributeName )
+ {
+ if( checkedElementName.equals( elementName ) ) {
+ String attribute = attributes.getValue( checkedAttributeName );
+ try {
+ Integer.parseInt( attribute );
+ } catch( NumberFormatException exception ) {
+ String message
+ = "Mandatory attribute \"{0}\" for element \"{1}\" is missing or not a valid integer";
+ Object[] arguments = new Object[] { checkedAttributeName, checkedElementName };
+ message = MessageFormat.format( message, arguments );
+ throw new IllegalArgumentException( message );
+ }
+ }
+ }
+
+ }
+
+}