You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by bo...@apache.org on 2012/05/17 14:43:52 UTC

svn commit: r1339576 - in /myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal: util/ webapp/

Author: bommel
Date: Thu May 17 12:43:51 2012
New Revision: 1339576

URL: http://svn.apache.org/viewvc?rev=1339576&view=rev
Log:
(TOBAGO-1138) Avoid using String.replace inside ResponseWriter

Added:
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JavascriptWriterUtils.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonWriterUtils.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/WriterUtils.java
Modified:
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/HtmlWriterUtils.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/HtmlResponseWriter.java
    myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/JsonResponseWriter.java

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/HtmlWriterUtils.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/HtmlWriterUtils.java?rev=1339576&r1=1339575&r2=1339576&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/HtmlWriterUtils.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/HtmlWriterUtils.java Thu May 17 12:43:51 2012
@@ -20,7 +20,7 @@ package org.apache.myfaces.tobago.intern
 import java.io.IOException;
 import java.io.Writer;
 
-public final class HtmlWriterUtils {
+public final class HtmlWriterUtils extends WriterUtils {
 
   private static final char[][] CHARS_TO_ESCAPE;
 
@@ -28,9 +28,8 @@ public final class HtmlWriterUtils {
     // init lookup table
     CHARS_TO_ESCAPE = new char[0xA0][];
 
-    final char[] empty = "".toCharArray();
     for (int i = 0; i < 0x20; i++) {
-      CHARS_TO_ESCAPE[i] = empty; // Control characters
+      CHARS_TO_ESCAPE[i] = EMPTY; // Control characters
     }
 
     CHARS_TO_ESCAPE['\t'] = "&#09;".toCharArray(); // Horizontal tabulator
@@ -42,44 +41,22 @@ public final class HtmlWriterUtils {
     CHARS_TO_ESCAPE['<'] = "&lt;".toCharArray();
     CHARS_TO_ESCAPE['>'] = "&gt;".toCharArray();
 
-    CHARS_TO_ESCAPE[0x7F] = empty; // Delete
+    CHARS_TO_ESCAPE[0x7F] = EMPTY; // Delete
 
     for (int i = 0x80; i < 0xA0; i++) {
-      CHARS_TO_ESCAPE[i] = empty; // Control characters
+      CHARS_TO_ESCAPE[i] = EMPTY; // Control characters
     }
 
     // all "normal" character positions contains null
   }
 
-  private final Writer out;
-
-  private final ResponseWriterBuffer buffer;
-
-  private final boolean utf8;
-
   public HtmlWriterUtils(final Writer out, final String characterEncoding) {
-    this.out = out;
-    utf8 = "utf-8".equalsIgnoreCase(characterEncoding);
-    buffer = new ResponseWriterBuffer(out);
+    super(out, characterEncoding);
   }
 
-  public void writeAttributeValue(final String text)
-      throws IOException {
-    writeEncodedValue(text.toCharArray(), 0, text.length(), true);
-  }
-
-  public void writeText(final String text) throws IOException {
-    writeEncodedValue(text.toCharArray(), 0, text.length(), false);
-  }
-
-  public void writeText(final char[] text, final int start, final int length)
-      throws IOException {
-    writeEncodedValue(text, start, length, false);
-  }
-
-  private void writeEncodedValue(final char[] text, final int start,
-      final int length, final boolean isAttribute)
-      throws IOException {
+  @Override
+  protected void writeEncodedValue(final char[] text, final int start,
+      final int length, final boolean isAttribute) throws IOException {
 
     int localIndex = -1;
 
@@ -91,6 +68,7 @@ public final class HtmlWriterUtils {
         break;
       }
     }
+    final Writer out = getOut();
 
     if (localIndex == -1) {
       // no need to escape
@@ -99,6 +77,8 @@ public final class HtmlWriterUtils {
       // write until localIndex and then encode the remainder
       out.write(text, start, localIndex);
 
+      final ResponseWriterBuffer buffer = getBuffer();
+
       for (int i = localIndex; i < end; i++) {
         final char ch = text[i];
 
@@ -113,7 +93,7 @@ public final class HtmlWriterUtils {
           } else {
             buffer.addToBuffer(ch);
           }
-        } else if (utf8) {
+        } else if (isUtf8()) {
           buffer.addToBuffer(ch);
         } else if (ch <= 0xff) {
           // ISO-8859-1 entities: encode as needed
@@ -137,186 +117,4 @@ public final class HtmlWriterUtils {
       buffer.flushBuffer();
     }
   }
-
-
-  /**
-   * Writes a character as a decimal escape.  Hex escapes are smaller than
-   * the decimal version, but Netscape didn't support hex escapes until
-   * 4.7.4.
-   */
-  private void writeDecRef(final char ch) throws IOException {
-    if (ch == '\u20ac') {
-      out.write("&euro;");
-      return;
-    }
-    out.write("&#");
-    // Formerly used String.valueOf().  This version tests out
-    // about 40% faster in a microbenchmark (and on systems where GC is
-    // going gonzo, it should be even better)
-    int i = (int) ch;
-    if (i > 10000) {
-      out.write('0' + (i / 10000));
-      i = i % 10000;
-      out.write('0' + (i / 1000));
-      i = i % 1000;
-      out.write('0' + (i / 100));
-      i = i % 100;
-      out.write('0' + (i / 10));
-      i = i % 10;
-      out.write('0' + i);
-    } else if (i > 1000) {
-      out.write('0' + (i / 1000));
-      i = i % 1000;
-      out.write('0' + (i / 100));
-      i = i % 100;
-      out.write('0' + (i / 10));
-      i = i % 10;
-      out.write('0' + i);
-    } else {
-      out.write('0' + (i / 100));
-      i = i % 100;
-      out.write('0' + (i / 10));
-      i = i % 10;
-      out.write('0' + i);
-    }
-
-    out.write(';');
-  }
-
-  public static boolean attributeValueMustEscaped(final String name) {
-    // this is 30% faster then the  .equals(name) version
-    // tested with 100 loops over 19871 names
-    //       (extracted from logfile over all demo pages)
-
-    try {
-      switch (name.charAt(0)) {
-        case 'i': // 'id'
-          if (name.length() == 2 && name.charAt(1) == 'd') {
-            return false;
-          }
-          break;
-        case 'n': // 'name'
-          if (name.length() == 4 && name.charAt(1) == 'a' && name.charAt(2) == 'm'
-              && name.charAt(3) == 'e') {
-            return false;
-          }
-          break;
-        case 'c': // 'class'
-          if (name.length() == 5 && name.charAt(1) == 'l' && name.charAt(2) == 'a'
-              && name.charAt(3) == 's' && name.charAt(4) == 's') {
-            return false;
-          }
-          break;
-        default:
-          return true;
-      }
-    } catch (NullPointerException e) {
-      // ignore
-    } catch (StringIndexOutOfBoundsException e) {
-      // ignore
-    }
-    return true;
-  }
-
-  //
-  // Entities from HTML 4.0, section 24.2.1; character codes 0xA0 to 0xFF
-  //
-  private static final char [][] ISO8859_1_ENTITIES = new char [][]{
-      "nbsp".toCharArray(),
-      "iexcl".toCharArray(),
-      "cent".toCharArray(),
-      "pound".toCharArray(),
-      "curren".toCharArray(),
-      "yen".toCharArray(),
-      "brvbar".toCharArray(),
-      "sect".toCharArray(),
-      "uml".toCharArray(),
-      "copy".toCharArray(),
-      "ordf".toCharArray(),
-      "laquo".toCharArray(),
-      "not".toCharArray(),
-      "shy".toCharArray(),
-      "reg".toCharArray(),
-      "macr".toCharArray(),
-      "deg".toCharArray(),
-      "plusmn".toCharArray(),
-      "sup2".toCharArray(),
-      "sup3".toCharArray(),
-      "acute".toCharArray(),
-      "micro".toCharArray(),
-      "para".toCharArray(),
-      "middot".toCharArray(),
-      "cedil".toCharArray(),
-      "sup1".toCharArray(),
-      "ordm".toCharArray(),
-      "raquo".toCharArray(),
-      "frac14".toCharArray(),
-      "frac12".toCharArray(),
-      "frac34".toCharArray(),
-      "iquest".toCharArray(),
-      "Agrave".toCharArray(),
-      "Aacute".toCharArray(),
-      "Acirc".toCharArray(),
-      "Atilde".toCharArray(),
-      "Auml".toCharArray(),
-      "Aring".toCharArray(),
-      "AElig".toCharArray(),
-      "Ccedil".toCharArray(),
-      "Egrave".toCharArray(),
-      "Eacute".toCharArray(),
-      "Ecirc".toCharArray(),
-      "Euml".toCharArray(),
-      "Igrave".toCharArray(),
-      "Iacute".toCharArray(),
-      "Icirc".toCharArray(),
-      "Iuml".toCharArray(),
-      "ETH".toCharArray(),
-      "Ntilde".toCharArray(),
-      "Ograve".toCharArray(),
-      "Oacute".toCharArray(),
-      "Ocirc".toCharArray(),
-      "Otilde".toCharArray(),
-      "Ouml".toCharArray(),
-      "times".toCharArray(),
-      "Oslash".toCharArray(),
-      "Ugrave".toCharArray(),
-      "Uacute".toCharArray(),
-      "Ucirc".toCharArray(),
-      "Uuml".toCharArray(),
-      "Yacute".toCharArray(),
-      "THORN".toCharArray(),
-      "szlig".toCharArray(),
-      "agrave".toCharArray(),
-      "aacute".toCharArray(),
-      "acirc".toCharArray(),
-      "atilde".toCharArray(),
-      "auml".toCharArray(),
-      "aring".toCharArray(),
-      "aelig".toCharArray(),
-      "ccedil".toCharArray(),
-      "egrave".toCharArray(),
-      "eacute".toCharArray(),
-      "ecirc".toCharArray(),
-      "euml".toCharArray(),
-      "igrave".toCharArray(),
-      "iacute".toCharArray(),
-      "icirc".toCharArray(),
-      "iuml".toCharArray(),
-      "eth".toCharArray(),
-      "ntilde".toCharArray(),
-      "ograve".toCharArray(),
-      "oacute".toCharArray(),
-      "ocirc".toCharArray(),
-      "otilde".toCharArray(),
-      "ouml".toCharArray(),
-      "divide".toCharArray(),
-      "oslash".toCharArray(),
-      "ugrave".toCharArray(),
-      "uacute".toCharArray(),
-      "ucirc".toCharArray(),
-      "uuml".toCharArray(),
-      "yacute".toCharArray(),
-      "thorn".toCharArray(),
-      "yuml".toCharArray()
-  };
 }

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JavascriptWriterUtils.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JavascriptWriterUtils.java?rev=1339576&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JavascriptWriterUtils.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JavascriptWriterUtils.java Thu May 17 12:43:51 2012
@@ -0,0 +1,118 @@
+package org.apache.myfaces.tobago.internal.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+public final class JavascriptWriterUtils extends WriterUtils {
+
+  private static final char[][] CHARS_TO_ESCAPE;
+
+  static {
+    // init lookup table
+    CHARS_TO_ESCAPE = new char[0xA0][];
+
+    for (int i = 0; i < 0x20; i++) {
+      CHARS_TO_ESCAPE[i] = EMPTY; // Control characters
+    }
+
+    CHARS_TO_ESCAPE['\t'] = "&#09;".toCharArray(); // Horizontal tabulator
+    CHARS_TO_ESCAPE['\n'] = "&#10;".toCharArray(); // Line feed
+    CHARS_TO_ESCAPE['\r'] = "&#13;".toCharArray(); // Carriage return
+
+    CHARS_TO_ESCAPE['"'] = "&quot;".toCharArray();
+    CHARS_TO_ESCAPE['\\'] = "\\\\".toCharArray();
+
+    CHARS_TO_ESCAPE[0x7F] = EMPTY; // Delete
+
+    for (int i = 0x80; i < 0xA0; i++) {
+      CHARS_TO_ESCAPE[i] = EMPTY; // Control characters
+    }
+
+    // all "normal" character positions contains null
+  }
+
+  public JavascriptWriterUtils(final Writer out, final String characterEncoding) {
+    super(out, characterEncoding);
+  }
+
+  @Override
+  protected void writeEncodedValue(final char[] text, final int start,
+      final int length, final boolean isAttribute) throws IOException {
+
+    int localIndex = -1;
+
+    final int end = start + length;
+    for (int i = start; i < end; i++) {
+      char ch = text[i];
+      if (ch >= CHARS_TO_ESCAPE.length || CHARS_TO_ESCAPE[ch] != null) {
+        localIndex = i;
+        break;
+      }
+    }
+    final Writer out = getOut();
+
+    if (localIndex == -1) {
+      // no need to escape
+      out.write(text, start, length);
+    } else {
+      // write until localIndex and then encode the remainder
+      out.write(text, start, localIndex);
+
+      final ResponseWriterBuffer buffer = getBuffer();
+
+      for (int i = localIndex; i < end; i++) {
+        final char ch = text[i];
+
+        // Tilde or less...
+        if (ch < CHARS_TO_ESCAPE.length) {
+          if (isAttribute && ch == '&' && (i + 1 < end) && text[i + 1] == '{') {
+            // HTML 4.0, section B.7.1: ampersands followed by
+            // an open brace don't get escaped
+            buffer.addToBuffer('&');
+          } else if (CHARS_TO_ESCAPE[ch] != null) {
+            buffer.addToBuffer(CHARS_TO_ESCAPE[ch]);
+          } else {
+            buffer.addToBuffer(ch);
+          }
+        } else if (isUtf8()) {
+          buffer.addToBuffer(ch);
+        } else if (ch <= 0xff) {
+          // ISO-8859-1 entities: encode as needed
+          buffer.flushBuffer();
+
+          out.write('&');
+          char[] chars = ISO8859_1_ENTITIES[ch - 0xA0];
+          out.write(chars, 0, chars.length);
+          out.write(';');
+        } else {
+          buffer.flushBuffer();
+
+          // Double-byte characters to encode.
+          // PENDING: when outputting to an encoding that
+          // supports double-byte characters (UTF-8, for example),
+          // we should not be encoding
+          writeDecRef(ch);
+        }
+      }
+
+      buffer.flushBuffer();
+    }
+  }
+}

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonWriterUtils.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonWriterUtils.java?rev=1339576&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonWriterUtils.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/JsonWriterUtils.java Thu May 17 12:43:51 2012
@@ -0,0 +1,122 @@
+package org.apache.myfaces.tobago.internal.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+
+public final class JsonWriterUtils extends WriterUtils {
+
+  private static final char[][] CHARS_TO_ESCAPE;
+
+  static {
+    // init lookup table
+    CHARS_TO_ESCAPE = new char[0xA0][];
+
+    for (int i = 0; i < 0x20; i++) {
+      CHARS_TO_ESCAPE[i] = EMPTY; // Control characters
+    }
+
+    CHARS_TO_ESCAPE['\t'] = "&#09;".toCharArray(); // Horizontal tabulator
+    CHARS_TO_ESCAPE['\n'] = "&#10;".toCharArray(); // Line feed
+    CHARS_TO_ESCAPE['\r'] = "&#13;".toCharArray(); // Carriage return
+
+    CHARS_TO_ESCAPE['"'] = "&quot;".toCharArray();
+    CHARS_TO_ESCAPE['&'] = "&amp;".toCharArray();
+    CHARS_TO_ESCAPE['<'] = "&lt;".toCharArray();
+    CHARS_TO_ESCAPE['>'] = "&gt;".toCharArray();
+    CHARS_TO_ESCAPE['\\'] = "\\\\".toCharArray();
+
+    CHARS_TO_ESCAPE[0x7F] = EMPTY; // Delete
+
+    for (int i = 0x80; i < 0xA0; i++) {
+      CHARS_TO_ESCAPE[i] = EMPTY; // Control characters
+    }
+
+    // all "normal" character positions contains null
+  }
+
+  public JsonWriterUtils(final Writer out, final String characterEncoding) {
+    super(out, characterEncoding);
+  }
+
+  @Override
+  protected void writeEncodedValue(final char[] text, final int start,
+      final int length, final boolean isAttribute) throws IOException {
+
+    int localIndex = -1;
+
+    final int end = start + length;
+    for (int i = start; i < end; i++) {
+      char ch = text[i];
+      if (ch >= CHARS_TO_ESCAPE.length || CHARS_TO_ESCAPE[ch] != null) {
+        localIndex = i;
+        break;
+      }
+    }
+    final Writer out = getOut();
+
+    if (localIndex == -1) {
+      // no need to escape
+      out.write(text, start, length);
+    } else {
+      // write until localIndex and then encode the remainder
+      out.write(text, start, localIndex);
+
+      final ResponseWriterBuffer buffer = getBuffer();
+
+      for (int i = localIndex; i < end; i++) {
+        final char ch = text[i];
+
+        // Tilde or less...
+        if (ch < CHARS_TO_ESCAPE.length) {
+          if (isAttribute && ch == '&' && (i + 1 < end) && text[i + 1] == '{') {
+            // HTML 4.0, section B.7.1: ampersands followed by
+            // an open brace don't get escaped
+            buffer.addToBuffer('&');
+          } else if (CHARS_TO_ESCAPE[ch] != null) {
+            buffer.addToBuffer(CHARS_TO_ESCAPE[ch]);
+          } else {
+            buffer.addToBuffer(ch);
+          }
+        } else if (isUtf8()) {
+          buffer.addToBuffer(ch);
+        } else if (ch <= 0xff) {
+          // ISO-8859-1 entities: encode as needed
+          buffer.flushBuffer();
+
+          out.write('&');
+          char[] chars = ISO8859_1_ENTITIES[ch - 0xA0];
+          out.write(chars, 0, chars.length);
+          out.write(';');
+        } else {
+          buffer.flushBuffer();
+
+          // Double-byte characters to encode.
+          // PENDING: when outputting to an encoding that
+          // supports double-byte characters (UTF-8, for example),
+          // we should not be encoding
+          writeDecRef(ch);
+        }
+      }
+
+      buffer.flushBuffer();
+    }
+  }
+}

Added: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/WriterUtils.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/WriterUtils.java?rev=1339576&view=auto
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/WriterUtils.java (added)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/util/WriterUtils.java Thu May 17 12:43:51 2012
@@ -0,0 +1,209 @@
+package org.apache.myfaces.tobago.internal.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+
+public abstract class WriterUtils {
+  protected static final char[] EMPTY = new char[0];
+  //
+  // Entities from HTML 4.0, section 24.2.1; character codes 0xA0 to 0xFF
+  //
+  protected static final char[][] ISO8859_1_ENTITIES = new char[][]{
+      "nbsp".toCharArray(),
+      "iexcl".toCharArray(),
+      "cent".toCharArray(),
+      "pound".toCharArray(),
+      "curren".toCharArray(),
+      "yen".toCharArray(),
+      "brvbar".toCharArray(),
+      "sect".toCharArray(),
+      "uml".toCharArray(),
+      "copy".toCharArray(),
+      "ordf".toCharArray(),
+      "laquo".toCharArray(),
+      "not".toCharArray(),
+      "shy".toCharArray(),
+      "reg".toCharArray(),
+      "macr".toCharArray(),
+      "deg".toCharArray(),
+      "plusmn".toCharArray(),
+      "sup2".toCharArray(),
+      "sup3".toCharArray(),
+      "acute".toCharArray(),
+      "micro".toCharArray(),
+      "para".toCharArray(),
+      "middot".toCharArray(),
+      "cedil".toCharArray(),
+      "sup1".toCharArray(),
+      "ordm".toCharArray(),
+      "raquo".toCharArray(),
+      "frac14".toCharArray(),
+      "frac12".toCharArray(),
+      "frac34".toCharArray(),
+      "iquest".toCharArray(),
+      "Agrave".toCharArray(),
+      "Aacute".toCharArray(),
+      "Acirc".toCharArray(),
+      "Atilde".toCharArray(),
+      "Auml".toCharArray(),
+      "Aring".toCharArray(),
+      "AElig".toCharArray(),
+      "Ccedil".toCharArray(),
+      "Egrave".toCharArray(),
+      "Eacute".toCharArray(),
+      "Ecirc".toCharArray(),
+      "Euml".toCharArray(),
+      "Igrave".toCharArray(),
+      "Iacute".toCharArray(),
+      "Icirc".toCharArray(),
+      "Iuml".toCharArray(),
+      "ETH".toCharArray(),
+      "Ntilde".toCharArray(),
+      "Ograve".toCharArray(),
+      "Oacute".toCharArray(),
+      "Ocirc".toCharArray(),
+      "Otilde".toCharArray(),
+      "Ouml".toCharArray(),
+      "times".toCharArray(),
+      "Oslash".toCharArray(),
+      "Ugrave".toCharArray(),
+      "Uacute".toCharArray(),
+      "Ucirc".toCharArray(),
+      "Uuml".toCharArray(),
+      "Yacute".toCharArray(),
+      "THORN".toCharArray(),
+      "szlig".toCharArray(),
+      "agrave".toCharArray(),
+      "aacute".toCharArray(),
+      "acirc".toCharArray(),
+      "atilde".toCharArray(),
+      "auml".toCharArray(),
+      "aring".toCharArray(),
+      "aelig".toCharArray(),
+      "ccedil".toCharArray(),
+      "egrave".toCharArray(),
+      "eacute".toCharArray(),
+      "ecirc".toCharArray(),
+      "euml".toCharArray(),
+      "igrave".toCharArray(),
+      "iacute".toCharArray(),
+      "icirc".toCharArray(),
+      "iuml".toCharArray(),
+      "eth".toCharArray(),
+      "ntilde".toCharArray(),
+      "ograve".toCharArray(),
+      "oacute".toCharArray(),
+      "ocirc".toCharArray(),
+      "otilde".toCharArray(),
+      "ouml".toCharArray(),
+      "divide".toCharArray(),
+      "oslash".toCharArray(),
+      "ugrave".toCharArray(),
+      "uacute".toCharArray(),
+      "ucirc".toCharArray(),
+      "uuml".toCharArray(),
+      "yacute".toCharArray(),
+      "thorn".toCharArray(),
+      "yuml".toCharArray()
+  };
+  private final Writer out;
+  private final ResponseWriterBuffer buffer;
+  private final boolean utf8;
+
+  public WriterUtils(final Writer out, final String characterEncoding) {
+    this.out = out;
+    buffer = new ResponseWriterBuffer(out);
+    utf8 = "utf-8".equalsIgnoreCase(characterEncoding);
+  }
+
+  public void writeAttributeValue(final String text)
+      throws IOException {
+    writeEncodedValue(text.toCharArray(), 0, text.length(), true);
+  }
+
+  public void writeText(final String text) throws IOException {
+    writeEncodedValue(text.toCharArray(), 0, text.length(), false);
+  }
+
+  public void writeText(final char[] text, final int start, final int length)
+      throws IOException {
+    writeEncodedValue(text, start, length, false);
+  }
+
+  protected abstract void writeEncodedValue(char[] text, int start,
+                                            int length, boolean isAttribute)
+      throws IOException;
+
+  /**
+   * Writes a character as a decimal escape.  Hex escapes are smaller than
+   * the decimal version, but Netscape didn't support hex escapes until
+   * 4.7.4.
+   */
+  protected void writeDecRef(final char ch) throws IOException {
+    if (ch == '\u20ac') {
+      out.write("&euro;");
+      return;
+    }
+    out.write("&#");
+    // Formerly used String.valueOf().  This version tests out
+    // about 40% faster in a microbenchmark (and on systems where GC is
+    // going gonzo, it should be even better)
+    int i = (int) ch;
+    if (i > 10000) {
+      out.write('0' + (i / 10000));
+      i = i % 10000;
+      out.write('0' + (i / 1000));
+      i = i % 1000;
+      out.write('0' + (i / 100));
+      i = i % 100;
+      out.write('0' + (i / 10));
+      i = i % 10;
+      out.write('0' + i);
+    } else if (i > 1000) {
+      out.write('0' + (i / 1000));
+      i = i % 1000;
+      out.write('0' + (i / 100));
+      i = i % 100;
+      out.write('0' + (i / 10));
+      i = i % 10;
+      out.write('0' + i);
+    } else {
+      out.write('0' + (i / 100));
+      i = i % 100;
+      out.write('0' + (i / 10));
+      i = i % 10;
+      out.write('0' + i);
+    }
+
+    out.write(';');
+  }
+
+  protected final Writer getOut() {
+    return out;
+  }
+
+  protected final ResponseWriterBuffer getBuffer() {
+    return buffer;
+  }
+
+  protected final boolean isUtf8() {
+    return utf8;
+  }
+}

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/HtmlResponseWriter.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/HtmlResponseWriter.java?rev=1339576&r1=1339575&r2=1339576&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/HtmlResponseWriter.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/HtmlResponseWriter.java Thu May 17 12:43:51 2012
@@ -19,6 +19,8 @@ package org.apache.myfaces.tobago.intern
 
 import org.apache.myfaces.tobago.component.Attributes;
 import org.apache.myfaces.tobago.internal.util.HtmlWriterUtils;
+import org.apache.myfaces.tobago.internal.util.JsonWriterUtils;
+import org.apache.myfaces.tobago.internal.util.WriterUtils;
 import org.apache.myfaces.tobago.renderkit.css.Style;
 import org.apache.myfaces.tobago.renderkit.html.HtmlElements;
 import org.apache.myfaces.tobago.util.FacesVersion;
@@ -35,15 +37,19 @@ public class HtmlResponseWriter extends 
   private static final String HTML_DOCTYPE =
       "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">";
 
-  private final HtmlWriterUtils helper;
+  private final WriterUtils helper;
 
   public HtmlResponseWriter(
       Writer writer, String contentType, String characterEncoding) {
     super(writer, contentType, characterEncoding);
-    this.helper = new HtmlWriterUtils(writer, characterEncoding);
+    if ("application/json".equals(contentType)) {
+      this.helper = new JsonWriterUtils(writer, characterEncoding);
+    } else {
+      this.helper = new HtmlWriterUtils(writer, characterEncoding);
+    }
   }
 
-  public final HtmlWriterUtils getHelper() {
+  public final WriterUtils getHelper() {
     return helper;
   }
 

Modified: myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/JsonResponseWriter.java
URL: http://svn.apache.org/viewvc/myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/JsonResponseWriter.java?rev=1339576&r1=1339575&r2=1339576&view=diff
==============================================================================
--- myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/JsonResponseWriter.java (original)
+++ myfaces/tobago/trunk/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/webapp/JsonResponseWriter.java Thu May 17 12:43:51 2012
@@ -18,8 +18,8 @@ package org.apache.myfaces.tobago.intern
  */
 
 import org.apache.commons.lang.StringUtils;
-import org.apache.myfaces.tobago.internal.ajax.AjaxInternalUtils;
 import org.apache.myfaces.tobago.internal.util.FastStringWriter;
+import org.apache.myfaces.tobago.internal.util.JavascriptWriterUtils;
 import org.apache.myfaces.tobago.util.FacesVersion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -34,26 +34,35 @@ public class JsonResponseWriter extends 
   private static final Logger LOG = LoggerFactory.getLogger(JsonResponseWriter.class);
 
   private Writer javascriptWriter;
-  private boolean javascriptMode;
+  private boolean javascriptBlock;
+  private JavascriptWriterUtils encodeInJavascriptBlock;
+  private JavascriptWriterUtils encodeOutsideJavascriptBlock;
 
   public JsonResponseWriter(Writer writer, String contentType, String characterEncoding) {
     super(writer, contentType, characterEncoding);
     this.javascriptWriter = new FastStringWriter();
+    this.encodeOutsideJavascriptBlock = new JavascriptWriterUtils(writer, characterEncoding);
+    this.encodeInJavascriptBlock = new JavascriptWriterUtils(javascriptWriter, characterEncoding);
   }
 
   @Override
   public void endJavascript() throws IOException {
-    javascriptMode = false;
+    javascriptBlock = false;
   }
 
   @Override
   public void startJavascript() throws IOException {
-    javascriptMode = true;
+    javascriptBlock = true;
   }
 
   @Override
   public void write(String string) throws IOException {
-    writeInternal(javascriptMode ? javascriptWriter : getWriter(), AjaxInternalUtils.encodeJavaScriptString(string));
+    closeOpenTag();
+    if (javascriptBlock) {
+      encodeInJavascriptBlock.writeText(string);
+    } else {
+      encodeOutsideJavascriptBlock.writeText(string);
+    }
   }
 
   @Override
@@ -74,7 +83,8 @@ public class JsonResponseWriter extends 
 
   @Override
   public void writeJavascript(String script) throws IOException {
-    writeInternal(javascriptWriter, AjaxInternalUtils.encodeJavaScriptString(script));
+    closeOpenTag();
+    encodeInJavascriptBlock.writeText(script);
   }
 
   public String getJavascript() {
@@ -133,10 +143,7 @@ public class JsonResponseWriter extends 
       writer.write(' ');
       writer.write(name);
       writer.write("=\\\"");
-      // todo: optimize for performance: replace
-      if (value.contains("\\")) {
-        value = value.replace("\\", "\\\\");
-      }
+
       if (escape) {
         getHelper().writeAttributeValue(value);
       } else {
@@ -149,11 +156,7 @@ public class JsonResponseWriter extends 
   public void writeText(final Object text, final String property)
       throws IOException {
     closeOpenTag();
-    // todo: optimize for performance: replace
     String value = findValue(text, property);
-    if (value.contains("\\")) {
-      value = value.replace("\\", "\\\\");
-    }
     getHelper().writeText(value);
   }