You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ra...@apache.org on 2008/07/28 23:43:43 UTC

svn commit: r680516 - in /commons/proper/scxml/branches/J6/src: main/java/org/apache/commons/scxml/SCXMLHelper.java main/java/org/apache/commons/scxml/io/SCXMLSerializer.java test/java/org/apache/commons/scxml/io/SCXMLSerializerTest.java

Author: rahul
Date: Mon Jul 28 14:43:36 2008
New Revision: 680516

URL: http://svn.apache.org/viewvc?rev=680516&view=rev
Log:
Port r680515 from trunk.
Serialization of expressions may produce invalid XML
Variant of a patch by Ingmar Kliche <ingmar dot kliche at googlemail dot com>. Thanks Ingmar!
SCXML-76

Modified:
    commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/SCXMLHelper.java
    commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java
    commons/proper/scxml/branches/J6/src/test/java/org/apache/commons/scxml/io/SCXMLSerializerTest.java

Modified: commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/SCXMLHelper.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/SCXMLHelper.java?rev=680516&r1=680515&r2=680516&view=diff
==============================================================================
--- commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/SCXMLHelper.java (original)
+++ commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/SCXMLHelper.java Mon Jul 28 14:43:36 2008
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.scxml;
 
+import java.io.StringWriter;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -459,6 +460,60 @@
     }
 
     /**
+     * Escape XML strings for serialization.
+     * The basic algorithm is taken from Commons Lang (see oacl.Entities.java)
+     *
+     * @param str A string to be escaped
+     * @return The escaped string
+     */
+    public static String escapeXML(final String str) {
+        if (str == null) {
+            return null;
+        }
+
+        // Make the writer an arbitrary bit larger than the source string
+        int len = str.length();
+        StringWriter stringWriter = new StringWriter(len + 8);
+
+        for (int i = 0; i < len; i++) {
+            char c = str.charAt(i);
+            String entityName = null; // Look for XML 1.0 predefined entities
+            switch (c) {
+                case '"':
+                    entityName = "quot";
+                    break;
+                case '&':
+                    entityName = "amp";
+                    break;
+                case '\'':
+                    entityName = "apos";
+                    break;
+                case '<':
+                    entityName = "lt";
+                    break;
+                case '>':
+                    entityName = "gt";
+                    break;
+            }
+            if (entityName == null) {
+                if (c > 0x7F) {
+                    stringWriter.write("&#");
+                    stringWriter.write(Integer.toString(c));
+                    stringWriter.write(';');
+                } else {
+                    stringWriter.write(c);
+                }
+            } else {
+                stringWriter.write('&');
+                stringWriter.write(entityName);
+                stringWriter.write(';');
+            }
+        }
+
+        return stringWriter.toString();
+    }
+
+    /**
      * Discourage instantiation since this is a utility class.
      */
     private SCXMLHelper() {
@@ -472,4 +527,3 @@
     private static final String NAMESPACES_KEY = "_ALL_NAMESPACES";
 
 }
-

Modified: commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java?rev=680516&r1=680515&r2=680516&view=diff
==============================================================================
--- commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java (original)
+++ commons/proper/scxml/branches/J6/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java Mon Jul 28 14:43:36 2008
@@ -214,7 +214,7 @@
         for (Param p : params) {
             b.append(indent).append(INDENT).append("<param name=\"").
                 append(p.getName()).append("\" expr=\"").
-                append(p.getExpr()).append("\"/>\n");
+                append(SCXMLHelper.escapeXML(p.getExpr())).append("\"/>\n");
         }
         Finalize f = i.getFinalize();
         if (f != null) {
@@ -280,7 +280,8 @@
             b.append(" event=\"").append(t.getEvent()).append("\"");
         }
         if (!SCXMLHelper.isStringEmpty(t.getCond())) {
-            b.append(" cond=\"").append(t.getCond()).append("\"");
+            b.append(" cond=\"").append(SCXMLHelper.escapeXML(t.getCond())).
+                append("\"");
         }
         boolean next = !SCXMLHelper.isStringEmpty(t.getNext());
         if (next) {
@@ -352,7 +353,8 @@
                 } else {
                     b.append(indent).append(INDENT).append("<data id=\"").
                         append(datum.getId()).append("\" expr=\"").
-                        append(datum.getExpr()).append("\" />\n");
+                        append(SCXMLHelper.escapeXML(datum.getExpr())).
+                        append("\" />\n");
                 }
             }
             b.append(indent).append("</datamodel>\n");
@@ -411,8 +413,9 @@
             if (a instanceof Var) {
                 Var v = (Var) a;
                 b.append(indent).append("<var name=\"").append(v.getName())
-                        .append("\" expr=\"").append(v.getExpr()).append(
-                                "\"/>\n");
+                    .append("\" expr=\"")
+                    .append(SCXMLHelper.escapeXML(v.getExpr()))
+                    .append("\"/>\n");
             } else if (a instanceof Assign) {
                 Assign asn = (Assign) a;
                 b.append(indent).append("<assign");
@@ -421,11 +424,13 @@
                     if (!SCXMLHelper.isStringEmpty(asn.getSrc())) {
                         b.append("\" src=\"").append(asn.getSrc());
                     } else {
-                        b.append("\" expr=\"").append(asn.getExpr());
+                        b.append("\" expr=\"").
+                            append(SCXMLHelper.escapeXML(asn.getExpr()));
                     }
                 } else {
                     b.append(" name=\"").append(asn.getName()).
-                        append("\" expr=\"").append(asn.getExpr());
+                        append("\" expr=\"").
+                        append(SCXMLHelper.escapeXML(asn.getExpr()));
                 }
                 b.append("\"/>\n");
             } else if (a instanceof Send) {
@@ -436,12 +441,13 @@
                     .append(c.getSendid()).append("\"/>\n");
             } else if (a instanceof Log) {
                 Log lg = (Log) a;
-                b.append(indent).append("<log expr=\"").append(lg.getExpr())
-                        .append("\"/>\n");
+                b.append(indent).append("<log expr=\"").
+                    append(SCXMLHelper.escapeXML(lg.getExpr())).
+                    append("\"/>\n");
             } else if (a instanceof Exit) {
                 Exit e = (Exit) a;
                 b.append(indent).append("<exit");
-                String expr = e.getExpr();
+                String expr = SCXMLHelper.escapeXML(e.getExpr());
                 String nl = e.getNamelist();
                 if (expr != null) {
                     b.append(" expr=\"" + expr + "\"");
@@ -459,7 +465,8 @@
             } else if (a instanceof ElseIf) {
                 ElseIf eif = (ElseIf) a;
                 b.append(indent).append("<elseif cond=\"")
-                        .append(eif.getCond()).append("\" />\n");
+                    .append(SCXMLHelper.escapeXML(eif.getCond()))
+                    .append("\" />\n");
             }
         }
         return exit;
@@ -526,8 +533,8 @@
      */
     public static void serializeIf(final StringBuffer b,
             final If iff, final String indent) {
-        b.append(indent).append("<if cond=\"").append(iff.getCond()).append(
-                "\">\n");
+        b.append(indent).append("<if cond=\"").append(SCXMLHelper.
+            escapeXML(iff.getCond())).append("\">\n");
         serializeActions(b, iff.getActions(), indent + INDENT);
         b.append(indent).append("</if>\n");
     }

Modified: commons/proper/scxml/branches/J6/src/test/java/org/apache/commons/scxml/io/SCXMLSerializerTest.java
URL: http://svn.apache.org/viewvc/commons/proper/scxml/branches/J6/src/test/java/org/apache/commons/scxml/io/SCXMLSerializerTest.java?rev=680516&r1=680515&r2=680516&view=diff
==============================================================================
--- commons/proper/scxml/branches/J6/src/test/java/org/apache/commons/scxml/io/SCXMLSerializerTest.java (original)
+++ commons/proper/scxml/branches/J6/src/test/java/org/apache/commons/scxml/io/SCXMLSerializerTest.java Mon Jul 28 14:43:36 2008
@@ -36,6 +36,7 @@
 import org.apache.commons.scxml.model.SCXML;
 import org.apache.commons.scxml.model.Send;
 import org.apache.commons.scxml.model.State;
+import org.apache.commons.scxml.model.Transition;
 import org.apache.commons.scxml.model.TransitionTarget;
 import org.apache.commons.scxml.model.Var;
 
@@ -288,4 +289,18 @@
         assertEquals(actualValue, returnValue.toString());
     }
 
+    public void testSerializeTransitionEscapeXML() {
+        Transition t = new Transition();
+
+        // note: the '<' char has to be escaped to "&lt;" to create valid XML
+        t.setCond("i < 3");
+
+        String actualValue = "<transition cond=\"i &lt; 3\">\n</transition>\n";
+
+        StringBuffer returnValue = new StringBuffer();
+        SCXMLSerializer.serializeTransition(returnValue, t, "");
+
+        assertEquals(actualValue, returnValue.toString());
+    }
+
 }