You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2012/01/11 23:23:28 UTC

svn commit: r1230285 - in /myfaces/core/trunk/shared/src: main/java/org/apache/myfaces/shared/renderkit/html/ main/java/org/apache/myfaces/shared/renderkit/html/util/ test/java/org/apache/myfaces/shared/renderkit/html/util/

Author: lu4242
Date: Wed Jan 11 22:23:28 2012
New Revision: 1230285

URL: http://svn.apache.org/viewvc?rev=1230285&view=rev
Log:
MYFACES-3445 [perf] reduce HtmlResponseWriterImpl overhead

Added:
    myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderWriterTest.java
      - copied, changed from r1214516, myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java
    myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoderTest.java   (with props)
Modified:
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java
    myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java

Modified: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java?rev=1230285&r1=1230284&r2=1230285&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java (original)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/HtmlResponseWriterImpl.java Wed Jan 11 22:23:28 2012
@@ -89,6 +89,7 @@ public class HtmlResponseWriterImpl
     
     private String _characterEncoding;
     private boolean _wrapScriptContentWithXmlCommentTag;
+    private boolean _isUTF8;
     
     private String _startElementName;
     private Boolean _isInsideScript;
@@ -190,6 +191,7 @@ public class HtmlResponseWriterImpl
             // canonize to uppercase, that's the standard format
             _characterEncoding = characterEncoding.toUpperCase();
         }
+        _isUTF8 = UTF8.equals(_characterEncoding);
     }
 
     public static boolean supportsContentType(String contentType)
@@ -655,8 +657,8 @@ public class HtmlResponseWriterImpl
             _currentWriter.write(' ');
             _currentWriter.write(name);
             _currentWriter.write("=\"");
-            _currentWriter.write(org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(
-                    strValue, false, false, !UTF8.equals(_characterEncoding)));
+            org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(_currentWriter,
+                    strValue, false, false, !_isUTF8);
             _currentWriter.write('"');
         }
     }
@@ -679,8 +681,8 @@ public class HtmlResponseWriterImpl
         _currentWriter.write("=\"");
         if (strValue.toLowerCase().startsWith("javascript:"))
         {
-            _currentWriter.write(org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(
-                    strValue, false, false, !UTF8.equals(_characterEncoding)));
+            org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(_currentWriter,
+                    strValue, false, false, !_isUTF8);
         }
         else
         {
@@ -712,9 +714,8 @@ public class HtmlResponseWriterImpl
             }
             */
             //_writer.write(strValue);
-            _currentWriter.write(
-                    org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encodeURIAtributte(
-                            strValue, _characterEncoding));
+            org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encodeURIAtributte(_currentWriter,
+                            strValue, _characterEncoding);
         }
         _currentWriter.write('"');
     }
@@ -746,19 +747,19 @@ public class HtmlResponseWriterImpl
         if (isScriptOrStyle())
         {
             // Don't bother encoding anything if chosen character encoding is UTF-8
-            if (UTF8.equals(_characterEncoding))
+            if (_isUTF8)
             {
                 _currentWriter.write(strValue);
             }
             else
             {
-                _currentWriter.write(UnicodeEncoder.encode(strValue));
+                UnicodeEncoder.encode(_currentWriter, strValue);
             }
         }
         else
         {
-            _currentWriter.write(org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(
-                    strValue, false, false, !UTF8.equals(_characterEncoding)));
+            org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(_currentWriter,
+                      strValue, false, false, !_isUTF8);
         }
     }
 
@@ -779,26 +780,26 @@ public class HtmlResponseWriterImpl
         {
             String strValue = new String(cbuf, off, len);
             // Don't bother encoding anything if chosen character encoding is UTF-8
-            if (UTF8.equals(_characterEncoding))
+            if (_isUTF8)
             {
                 _currentWriter.write(strValue);
             }
             else
             {
-                _currentWriter.write(UnicodeEncoder.encode(strValue));
+                UnicodeEncoder.encode(_currentWriter, strValue);
             }
         }
         else if (isTextarea())
         {
             // For textareas we must *not* map successive spaces to &nbsp or Newlines to <br/>
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(
-                    cbuf, off, len, false, false, !UTF8.equals(_characterEncoding), _currentWriter);
+                    cbuf, off, len, false, false, !_isUTF8, _currentWriter);
         }
         else
         {
             // We map successive spaces to &nbsp; and Newlines to <br/>
             org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder.encode(
-                    cbuf, off, len, true, true, !UTF8.equals(_characterEncoding), _currentWriter);
+                    cbuf, off, len, true, true, !_isUTF8, _currentWriter);
         }
     }
 
@@ -896,15 +897,14 @@ public class HtmlResponseWriterImpl
     public void write(char cbuf[], int off, int len) throws IOException
     {
         closeStartTagIfNecessary();
-        String strValue = new String(cbuf, off, len);
         // Don't bother encoding anything if chosen character encoding is UTF-8
-        if (UTF8.equals(_characterEncoding))
+        if (_isUTF8)
         {
-            _currentWriter.write(strValue);
+            _currentWriter.write(cbuf, off, len);
         }
         else
         {
-            _currentWriter.write(UnicodeEncoder.encode(strValue));
+            UnicodeEncoder.encode(_currentWriter, cbuf, off, len);
         }
     }
 
@@ -917,15 +917,14 @@ public class HtmlResponseWriterImpl
     public void write(char cbuf[]) throws IOException
     {
         closeStartTagIfNecessary();
-        String strValue = new String(cbuf);
         // Don't bother encoding anything if chosen character encoding is UTF-8
-        if (UTF8.equals(_characterEncoding))
+        if (_isUTF8)
         {
-            _currentWriter.write(strValue);
+            _currentWriter.write(cbuf);
         }
         else
         {
-            _currentWriter.write(UnicodeEncoder.encode(strValue));
+            UnicodeEncoder.encode(_currentWriter, cbuf, 0, cbuf.length);
         }
     }
 
@@ -937,13 +936,13 @@ public class HtmlResponseWriterImpl
         if (str.length() > 0)
         {
             // Don't bother encoding anything if chosen character encoding is UTF-8
-            if (UTF8.equals(_characterEncoding))
+            if (_isUTF8)
             {
                 _currentWriter.write(str);
             }
             else
             {
-                _currentWriter.write(UnicodeEncoder.encode(str));
+                UnicodeEncoder.encode(_currentWriter, str);
             }
         }
     }
@@ -951,15 +950,14 @@ public class HtmlResponseWriterImpl
     public void write(String str, int off, int len) throws IOException
     {
         closeStartTagIfNecessary();
-        String strValue = str.substring(off, off+len);
         // Don't bother encoding anything if chosen character encoding is UTF-8
-        if (UTF8.equals(_characterEncoding))
+        if (_isUTF8)
         {
-            _currentWriter.write(strValue);
+            _currentWriter.write(str, off, len);
         }
         else
         {
-            _currentWriter.write(UnicodeEncoder.encode(strValue));
+            UnicodeEncoder.encode(_currentWriter, str, off, len);
         }
     }
     

Modified: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java?rev=1230285&r1=1230284&r2=1230285&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java (original)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoder.java Wed Jan 11 22:23:28 2012
@@ -156,6 +156,144 @@ public abstract class HTMLEncoder
             return sb.toString();
         }
     }
+    
+    /**
+     * Variant of {@link #encode} where encodeNewline is false and encodeNbsp is true.
+     */
+    public static void encode (Writer writer, String string) throws IOException
+    {
+        encode(writer, string, false, true);
+    }
+
+    /**
+     * Variant of {@link #encode} where encodeNbsp is true.
+     */
+    public static void encode (Writer writer, String string, boolean encodeNewline) throws IOException
+    {
+        encode(writer, string, encodeNewline, true);
+    }
+
+    /**
+     * Variant of {@link #encode} where encodeNbsp and encodeNonLatin are true 
+     */
+    public static void encode (Writer writer, String string, 
+            boolean encodeNewline, boolean encodeSubsequentBlanksToNbsp) throws IOException
+    {
+        encode(writer, string, encodeNewline, encodeSubsequentBlanksToNbsp, true);
+    }
+    
+    public static void encode (Writer writer, String string,
+                                 boolean encodeNewline,
+                                 boolean encodeSubsequentBlanksToNbsp,
+                                 boolean encodeNonLatin) throws IOException
+    {
+        if (string == null)
+        {
+            return;
+        }
+
+        int start = 0;
+        String app;
+        char c;
+        for (int i = 0; i < string.length (); ++i)
+        {
+            app = null;
+            c = string.charAt(i);
+            
+            // All characters before letters
+            if ((int)c < 0x41)
+            {
+                switch (c)
+                {
+                    case '"': app = "&quot;"; break;    //"
+                    case '&': app = "&amp;"; break;     //&
+                    case '<': app = "&lt;"; break;      //<
+                    case '>': app = "&gt;"; break;      //>
+                    case ' ':
+                        if (encodeSubsequentBlanksToNbsp &&
+                                (i == 0 || (i - 1 >= 0 && string.charAt(i - 1) == ' ')))
+                        {
+                            //Space at beginning or after another space
+                            app = "&#160;";
+                        }
+                        break;
+                    case '\n':
+                        if (encodeNewline)
+                        {
+                            app = "<br/>";
+                        }
+                        break;
+                    default:
+                        break;
+                }
+            }
+            else if (encodeNonLatin && (int)c > 0x80)
+            {
+                 switch(c)
+                 {
+                    //german umlauts
+                    case '\u00E4' : app = "&auml;";  break;
+                    case '\u00C4' : app = "&Auml;";  break;
+                    case '\u00F6' : app = "&ouml;";  break;
+                    case '\u00D6' : app = "&Ouml;";  break;
+                    case '\u00FC' : app = "&uuml;";  break;
+                    case '\u00DC' : app = "&Uuml;";  break;
+                    case '\u00DF' : app = "&szlig;"; break;
+
+                    //misc
+                    //case 0x80: app = "&euro;"; break;  sometimes euro symbol is ascii 128, should we suport it?
+                    case '\u20AC': app = "&euro;";  break;
+                    case '\u00AB': app = "&laquo;"; break;
+                    case '\u00BB': app = "&raquo;"; break;
+                    case '\u00A0': app = "&#160;"; break;
+
+                    default :
+                        //encode all non basic latin characters
+                        app = "&#" + ((int)c) + ";";
+                    break;
+                }
+            }
+            if (app != null)
+            {
+                //if (sb == null)
+                //{
+                //    sb = new StringBuilder(string.substring(0, i));
+                //}
+                //sb.append(app);
+                if (start < i)
+                {
+                    writer.write(string, start, i-start);
+                }
+                start = i+1;
+                writer.write(app);
+            }
+            //else
+            //{
+            //    if (sb != null)
+            //    {
+            //        sb.append(c);
+            //    }
+            //}
+        }
+
+        //if (sb == null)
+        //{
+        //    return string;
+        //}
+        //else
+        //{
+        //    return sb.toString();
+        //}
+        if (start == 0)
+        {
+            writer.write(string);
+        }
+        else if (start < string.length())
+        {
+            writer.write(string,start,string.length()-start);
+        }
+    }
+
 
     /**
      * Variant of {@link #encode} where encodeNewline is false and encodeNbsp is true.
@@ -203,9 +341,10 @@ public abstract class HTMLEncoder
         offset = Math.max(0, offset);
         int realLength = Math.min(length, string.length - offset);
 
-        StringBuilder sb = null;    //create later on demand
+        //StringBuilder sb = null;    //create later on demand
         String app;
         char c;
+        int start = offset;
         
         for (int i = offset; i < offset + realLength; ++i)
         {
@@ -267,29 +406,44 @@ public abstract class HTMLEncoder
             }
             if (app != null)
             {
-                if (sb == null)
+                //if (sb == null)
+                //{
+                //    sb = new StringBuilder(realLength*2);
+                //    sb.append(string, offset, i - offset);
+                //}
+                //sb.append(app);
+                if (start < i)
                 {
-                    sb = new StringBuilder(realLength*2);
-                    sb.append(string, offset, i - offset);
+                    writer.write(string, start, i-start);
                 }
-                sb.append(app);
+                start = i+1;
+                writer.write(app);
             }
+            /*
             else
             {
                 if (sb != null)
                 {
                     sb.append(c);
                 }
-            }
+            }*/
         }
 
-        if (sb == null)
+        //if (sb == null)
+        //{
+        //    writer.write(string, offset, realLength);
+        //}
+        //else
+        //{
+        //    writer.write(sb.toString());
+        //}
+        if (start == offset)
         {
             writer.write(string, offset, realLength);
         }
-        else
+        else if (start < offset+realLength)
         {
-            writer.write(sb.toString());
+            writer.write(string,start,offset+realLength-start);
         }
     }
     
@@ -546,7 +700,7 @@ public abstract class HTMLEncoder
     private static String percentEncodeNonUsAsciiCharacter(char c, String characterEncoding)
     {
         ByteArrayOutputStream baos = new ByteArrayOutputStream(10);
-        StringBuffer builder = new StringBuffer();
+        StringBuilder builder = new StringBuilder();
         try
         {
             OutputStreamWriter writer = new OutputStreamWriter(baos,characterEncoding);
@@ -687,4 +841,480 @@ public abstract class HTMLEncoder
             return sb.toString();
         }
     }
+
+    /**
+     * Encode an URI, escaping or percent-encoding all required characters and
+     * following the rules mentioned on RFC 3986.  
+     * 
+     * @param string
+     * @param encodeNonLatin
+     * @return
+     * @throws IOException
+     */
+    public static void encodeURIAtributte(Writer writer, final String string, final String characterEncoding)
+        throws IOException
+    {
+        //StringBuilder sb = null;    //create later on demand
+        int start = 0;
+        String app;
+        char c;
+        boolean endLoop = false;
+        for (int i = 0; i < string.length (); ++i)
+        {
+            app = null;
+            c = string.charAt(i);
+            
+            // This are the guidelines to be taken into account by this algorithm to encode:
+            
+            // RFC 2396 Section 2.4.3 Excluded US-ASCII Characters
+            //
+            // control     = <US-ASCII coded characters 00-1F and 7F hexadecimal>
+            // space       = <US-ASCII coded character 20 hexadecimal>
+            // delims      = "<" | ">" | "#" | "%" | <">
+            //               %3C   %3E   %23   %25   %22
+            // unwise      = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
+            //               %7D   %7B   %7C   %5C   %5E   %5B   %5D   %60
+            //
+            // ".... Data corresponding to excluded characters must be escaped in order to
+            // be properly represented within a URI....."
+            
+            // RFC 3986 Section 3.  Syntax Components
+            //
+            // "... The generic URI syntax consists of a hierarchical sequence of
+            // components referred to as the scheme, authority, path, query, and
+            // fragment.
+            //
+            //   URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+            //
+            //   hier-part   = "//" authority path-abempty
+            //               / path-absolute
+            //               / path-rootless
+            //               / path-empty
+            // ...."
+            
+            // RFC 3986 Section 2.2:
+            // Reserved characters (should not be percent-encoded)
+            // reserved    = gen-delims / sub-delims
+            // gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+            //               %3A   %2F   %3F   %23   %5B   %5D   %40
+            // sub-delims  = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
+            //               %21   %24   %26   %27   %28   %29   %2A   %2B   %2C   %3B   %3D
+            
+            // Note than chars "[" and "]" are mentioned as they should be escaped on RFC 2396,
+            // but on the part D. Changes from RFC 2396 says about this chars (used on IPv6) 
+            // "...those rules were redefined to directly specify the characters allowed...."
+            // There is also other characters moved from excluded list to reserved:
+            // "[" / "]" / "#"  
+            
+            // RFC 3986 Section 2.3:
+            // "... for consistency, percent-encoded octets in the ranges of ALPHA
+            // (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E),
+            // underscore (%5F), or tilde (%7E) should not be created by URI
+            // producers...."
+            
+            // RFC 3986 Section  3.2.2.  Host
+
+            // host = IP-literal / IPv4address / reg-name
+
+            // The reg-name syntax allows percent-encoded octets in order to
+            // represent non-ASCII registered names in a uniform way that is
+            // independent of the underlying name resolution technology.  Non-ASCII
+            // characters must first be encoded according to UTF-8 [STD63], and then
+            // each octet of the corresponding UTF-8 sequence must be percent-
+            // encoded to be represented as URI characters.  URI producing
+            // applications must not use percent-encoding in host unless it is used
+            // to represent a UTF-8 character sequence.
+            
+            // RFC 3986 Section 3.4 Query 
+            //         query       = *( pchar / "/" / "?" )
+            //
+            // "...  However, as query components are often used to carry identifying information 
+            // in the form of "key=value" pairs and one frequently used value is a reference to
+            // another URI, it is sometimes better for usability to avoid percent-encoding those characters....."
+            //
+            // RFC 3986 Section 2.5 Identifying Data (Apply to query section)
+            //
+            // When a new URI scheme defines a component that represents textual
+            // data consisting of characters from the Universal Character Set [UCS],
+            // the data should first be encoded as octets according to the UTF-8
+            // character encoding [STD63]; then only those octets that do not
+            // correspond to characters in the unreserved set should be percent-
+            // encoded.  For example, the character A would be represented as "A",
+            // the character LATIN CAPITAL LETTER A WITH GRAVE would be represented
+            // as "%C3%80", and the character KATAKANA LETTER A would be represented
+            // as "%E3%82%A2".
+            //
+            // RFC 3986 Section 3.5 Fragment
+            //         fragment    = *( pchar / "/" / "?" )
+            //
+            // Note that follows the same as query
+            
+            // Based on the extracts the strategy to apply on this method is:
+            // 
+            // On scheme ":" hier-part
+            //
+            // Escape or percent encode chars inside :
+            // 
+            // - From %00 to %20, 
+            // - <"> %22, "%" %25 (If there is encode of "%", there is a risk of 
+            //                     duplicate encoding, encode it when we are sure 
+            //                     that there are not encoded twice)
+            // - "<" %3C, ">" %3E
+            // - "\" %5C, "^" %5E, "`" %60 
+            // - "{" %7B, "|" %7C, "}" %7D
+            // - From %7F ad infinitum (characters from %100 to infinitum should not be used in this
+            //   part of an URI, but it is preferred to encode it that omit it).
+            //
+            // The remaining characters must not be encoded
+            //
+            // Characters after ? or # should be percent encoding but only the necessary ones:
+            //
+            // - From %00 to %20 (' ' %20 could encode as +, but %20 also works, so we keep %20)
+            // - <"> %22, "%" %25 (If there is encode of "%", there is a risk of 
+            //                     duplicate encoding, encode it when we are sure 
+            //                     that there are not encoded twice)
+            // - "<" %3C, ">" %3E,
+            // - "\" %5C, "^" %5E, "`" %60 
+            // - "{" %7B, "|" %7C, "}" %7D
+            // - From %7F ad infinitum (each character as many bytes as necessary but take into account
+            //   that a single char should contain 2,3 or more bytes!. This data should be encoded 
+            //   translating from the document character encoding to percent encoding, because this values
+            //   could be retrieved from httpRequest.getParameter() and it uses the current character encoding
+            //   for decode values)
+            //
+            // "&" should be encoded as "&amp;" because this link is inside an html page, and 
+            // put only & is invalid in this context.
+
+            if (   (c <= (char)0x20) || (c >= (char)0x7F) || 
+                    c == '"' || c == '<' ||
+                    c == '>' || c == '\\' || c == '^' || c == '`' ||
+                    c == '{' || c == '|' || c == '}')
+            {
+                // The percent encoding on this part should be done using UTF-8 charset
+                // as RFC 3986 Section 3.2.2 says.
+                // Also there is a reference on 
+                // http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars
+                // that recommend use of UTF-8 instead the document character encoding.
+                // Jetty set by default UTF-8 (see http://jira.codehaus.org/browse/JETTY-113)
+                //app = percentEncode(c, "UTF-8");
+                if (start < i)
+                {
+                    writer.write(string, start, i-start);
+                }
+                start = i+1;
+                percentEncode(writer, c, "UTF-8");
+            }
+            else if (c == '%')
+            {
+                if (i + 2 < string.length())
+                {
+                    char c1 = string.charAt(i+1);
+                    char c2 = string.charAt(i+2);
+                    if ((( c1 >= '0' && c1 <='9') || (c1 >='A' && c1 <='Z')) &&
+                        (( c2 >= '0' && c2 <='9') || (c2 >='A' && c2 <='Z')))
+                    {
+                        // do not percent encode, because it could be already encoded
+                        // and we don't want encode it twice
+                    }
+                    else
+                    {
+                        //app = percentEncode(c, UTF8);
+                        if (start < i)
+                        {
+                            writer.write(string, start, i-start);
+                        }
+                        start = i+1;
+                        percentEncode(writer, c, UTF8);
+                    }
+                }
+                else
+                {
+                    //app = percentEncode(c, UTF8);
+                    if (start < i)
+                    {
+                        writer.write(string, start, i-start);
+                    }
+                    start = i+1;
+                    percentEncode(writer, c, UTF8);
+                }
+            }
+            else if (c == '?' || c == '#')
+            {
+                if (i+1 < string.length())
+                {
+                    // The remaining part of the URI are data that should be encoded
+                    // using the document character encoding.
+                    //app = c + encodeURIQuery(string.substring(i+1), characterEncoding);
+                    if (start < i)
+                    {
+                        writer.write(string, start, i-start);
+                    }
+                    start = i+1;
+                    writer.write(c);
+                    //encodeURIQuery(writer, string.substring(i+1), characterEncoding);
+                    encodeURIQuery(writer, string, i+1, characterEncoding);
+                    endLoop = true;
+                }
+            }
+            else
+            {
+                //No encoding, just do nothing, char will be added later.
+            }
+                        
+            if (app != null)
+            {
+                //if (sb == null)
+                //{
+                //    sb = new StringBuilder(string.substring(0, i));
+                //}
+                //sb.append(app);
+                if (start < i)
+                {
+                    writer.write(string, start, i-start);
+                }
+                start = i+1;
+                writer.write(app);
+            }
+            //else
+            //{
+            //    if (sb != null)
+            //    {
+            //        sb.append(c);
+            //    }
+            //}
+            if (endLoop)
+            {
+                start = string.length();
+                break;
+            }
+        }
+        //if (sb == null)
+        //{
+        //    return string;
+        //}
+        //else
+        //{
+        //    return sb.toString();
+        //}
+        if (start == 0)
+        {
+            writer.write(string);
+        }
+        else if (start < string.length())
+        {
+            writer.write(string,start,string.length()-start);
+        }
+    }
+
+    /**
+     * Encode a unicode char value in percentEncode, decoding its bytes using a specified 
+     * characterEncoding.
+     * 
+     * @param c
+     * @param characterEncoding
+     * @return
+     */
+    private static void percentEncode(Writer writer, char c, String characterEncoding) throws IOException
+    {
+        String app = null;
+        if (c > (char)((short)0x007F))
+        {
+            //percent encode in the proper encoding to be consistent
+            //app = percentEncodeNonUsAsciiCharacter(writer c, characterEncoding);
+            percentEncodeNonUsAsciiCharacter(writer, c, characterEncoding);
+        }
+        else
+        {
+            //percent encode US-ASCII char (0x00-0x7F range)
+            //app = "%" + HEX_CHARSET.charAt( ((c >> 0x4) % 0x10)) +HEX_CHARSET.charAt(c % 0x10);
+            writer.write('%');
+            writer.write(HEX_CHARSET.charAt( ((c >> 0x4) % 0x10)));
+            writer.write(HEX_CHARSET.charAt(c % 0x10));
+        }
+        //return app;
+    }
+    
+    private static void percentEncodeNonUsAsciiCharacter(Writer currentWriter, char c, String characterEncoding) throws IOException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(10);
+        StringBuilder builder = new StringBuilder();
+        try
+        {
+            OutputStreamWriter writer = new OutputStreamWriter(baos,characterEncoding);
+            writer.write(c);
+            writer.flush();
+        }
+        catch(IOException e)
+        {
+            baos.reset();
+            return;
+        }
+        
+        byte [] byteArray =  baos.toByteArray();
+        for (int i=0; i < byteArray.length; i++)
+        {
+            //builder.append('%');
+            //builder.append(HEX_CHARSET.charAt( (( ((short) byteArray[i] & 0xFF ) >> 0x4) % 0x10)) );
+            //builder.append(HEX_CHARSET.charAt( ((short) byteArray[i] & 0xFF ) % 0x10));
+            currentWriter.write('%');
+            currentWriter.write(HEX_CHARSET.charAt( (( ((short) byteArray[i] & 0xFF ) >> 0x4) % 0x10)) );
+            currentWriter.write(HEX_CHARSET.charAt( ((short) byteArray[i] & 0xFF ) % 0x10));
+        }
+        
+        //return builder.toString();
+    }
+    
+    /**
+     * Encode the query part using the document charset encoding provided.
+     * 
+     * 
+     * @param string
+     * @param characterEncoding
+     * @return
+     */
+    private static void encodeURIQuery(Writer writer, final String string, int offset, final String characterEncoding)
+            throws IOException
+    {
+        //StringBuilder sb = null;    //create later on demand
+        int start = offset;
+        int realLength = string.length()-offset;
+        String app;
+        char c;
+        //boolean endLoop = false;
+        for (int i = offset; i < offset+realLength; ++i)
+        {
+            app = null;
+            c = string.charAt(i);
+            
+            // - From %00 to %20 (' ' %20 could encode as +, but %20 also works, so we keep %20)
+            // - <"> %22 (If there is encode of "%", there is a risk of duplicate encoding, so 
+            //            we make easier and omit this one)
+            // - "<" %3C, ">" %3E,
+            // - "\" %5C, "^" %5E, "`" %60 
+            // - "{" %7B, "|" %7C, "}" %7D
+            // - From %7F ad infinitum (each character as many bytes as necessary but take into account
+            //   that a single char should contain 2,3 or more bytes!. This data should be encoded 
+            //   translating from the document character encoding to percent encoding)
+            //
+            // "&" should be encoded as "&amp;" because this link is inside an html page, and 
+            // put & is invalid in this context   
+            
+            if (   (c <= (char)0x20) || (c >= (char)0x7F) || 
+                    c == '"' || c == '<' ||
+                    c == '>' || c == '\\' || c == '^' || c == '`' ||
+                    c == '{' || c == '|' || c == '}')
+            {
+                // The percent encoding on this part should be done using UTF-8 charset
+                // as RFC 3986 Section 3.2.2 says
+                //app = percentEncode(c, characterEncoding);
+                if (start < i)
+                {
+                    writer.write(string, start, i-start);
+                }
+                start = i+1;
+                percentEncode(writer, c, characterEncoding);
+            }
+            else if (c == '%')
+            {
+                if (i + 2 < string.length())
+                {
+                    char c1 = string.charAt(i+1);
+                    char c2 = string.charAt(i+2);
+                    if ((( c1 >= '0' && c1 <='9') || (c1 >='A' && c1 <='Z')) &&
+                        (( c2 >= '0' && c2 <='9') || (c2 >='A' && c2 <='Z')))
+                    {
+                        // do not percent encode, because it could be already encoded
+                    }
+                    else
+                    {
+                        //app = percentEncode(c, characterEncoding);
+                        if (start < i)
+                        {
+                            writer.write(string, start, i-start);
+                        }
+                        start = i+1;
+                        percentEncode(writer, c, characterEncoding);
+                    }
+                }
+                else
+                {
+                    //app = percentEncode(c, characterEncoding);
+                    if (start < i)
+                    {
+                        writer.write(string, start, i-start);
+                    }
+                    start = i+1;
+                    percentEncode(writer, c, characterEncoding);
+                }
+            }
+            else if (c == '&')
+            {
+                if (i+4 < string.length() )
+                {
+                    if ('a' == string.charAt(i+1) &&
+                        'm' == string.charAt(i+2) &&
+                        'p' == string.charAt(i+3) &&
+                        ';' == string.charAt(i+4))
+                    {
+                        //Skip
+                    }
+                    else
+                    {
+                        app = "&amp;";
+                    }
+                }
+                else
+                {
+                    app = "&amp;";
+                }
+            }
+            else
+            {
+                //No encoding, just do nothing, char will be added later.
+            }
+                        
+            if (app != null)
+            {
+                //if (sb == null)
+                //{
+                //    sb = new StringBuilder(string.substring(0, i));
+                //}
+                //sb.append(app);
+                if (start < i)
+                {
+                    writer.write(string, start, i-start);
+                }
+                start = i+1;
+                writer.write(app);
+            }
+            //else
+            //{
+            //    if (sb != null)
+            //    {
+            //        sb.append(c);
+            //    }
+            //}
+            //if (endLoop)
+            //{
+            //    break;
+            //}
+        }
+        
+        //if (sb == null)
+        //{
+        //    return string;
+        //}
+        //else
+        //{
+        //    return sb.toString();
+        //}
+        if (start == offset)
+        {
+            writer.write(string, offset, realLength);
+        }
+        else if (start < offset+realLength)
+        {
+            writer.write(string,start,offset+realLength-start);
+        }
+    }
 }

Modified: myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java?rev=1230285&r1=1230284&r2=1230285&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java (original)
+++ myfaces/core/trunk/shared/src/main/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoder.java Wed Jan 11 22:23:28 2012
@@ -18,6 +18,9 @@
  */
 package org.apache.myfaces.shared.renderkit.html.util;
 
+import java.io.IOException;
+import java.io.Writer;
+
 /**
  * Converts characters outside of latin-1 set in a string to numeric character references.
  * 
@@ -60,6 +63,112 @@ public abstract class UnicodeEncoder
 
         return sb != null ? sb.toString() : string;
     }
+    
+    public static void encode (Writer writer, String string) throws IOException
+    {
+        if (string == null)
+        {
+            return;
+        }
+
+        int start = 0;
+        char c;
+        for (int i = 0; i < string.length (); ++i)
+        {
+            c = string.charAt(i);
+            if (((int)c) >= 0x80)
+            {
+                if (start < i)
+                {
+                    writer.write(string, start, i-start);
+                }
+                start = i+1;
+                //encode all non basic latin characters
+                writer.write("&#");
+                writer.write(Integer.toString((int)c));
+                writer.write(";");
+            }
+        }
+
+        if (start == 0)
+        {
+            writer.write(string);
+        }
+        else if (start < string.length())
+        {
+            writer.write(string,start,string.length()-start);
+        }
+    }
+
+    public static void encode (Writer writer, char[] cbuf, int off, int len) throws IOException
+    {
+        if (cbuf == null)
+        {
+            return;
+        }
+
+        int start = off;
+        char c;
+        for (int i = off; i < off+len; ++i)
+        {
+            c = cbuf[i];
+            if (((int)c) >= 0x80)
+            {
+                if (start < i)
+                {
+                    writer.write(cbuf, start, i-start);
+                }
+                start = i+1;
+                //encode all non basic latin characters
+                writer.write("&#");
+                writer.write(Integer.toString((int)c));
+                writer.write(";");
+            }
+        }
+
+        if (start == off)
+        {
+            writer.write(cbuf, off, len);
+        }
+        else if (start < off+len)
+        {
+            writer.write(cbuf,start,off+len-start);
+        }
+    }
+    
+    public static void encode (Writer writer, String cbuf, int off, int len) throws IOException
+    {
+        if (cbuf == null)
+        {
+            return;
+        }
 
+        int start = off;
+        char c;
+        for (int i = off; i < off+len; ++i)
+        {
+            c = cbuf.charAt(i);
+            if (((int)c) >= 0x80)
+            {
+                if (start < i)
+                {
+                    writer.write(cbuf, start, i-start);
+                }
+                start = i+1;
+                //encode all non basic latin characters
+                writer.write("&#");
+                writer.write(Integer.toString((int)c));
+                writer.write(";");
+            }
+        }
 
+        if (start == off)
+        {
+            writer.write(cbuf, off, len);
+        }
+        else if (start < off+len)
+        {
+            writer.write(cbuf,start,off+len-start);
+        }
+    }
 }

Copied: myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderWriterTest.java (from r1214516, myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderWriterTest.java?p2=myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderWriterTest.java&p1=myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java&r1=1214516&r2=1230285&rev=1230285&view=diff
==============================================================================
--- myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderTest.java (original)
+++ myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/HTMLEncoderWriterTest.java Wed Jan 11 22:23:28 2012
@@ -16,13 +16,9 @@
 
 package org.apache.myfaces.shared.renderkit.html.util;
 
-import java.io.ByteArrayOutputStream;
 import java.io.CharArrayWriter;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
+import java.io.StringWriter;
 
 import org.apache.myfaces.test.base.AbstractJsfTestCase;
 
@@ -32,7 +28,7 @@ import org.apache.myfaces.test.base.Abst
  * @author Michael Kurz (latest modification by $Author$)
  * @version $Revision$ $Date$
  */
-public class HTMLEncoderTest extends AbstractJsfTestCase {
+public class HTMLEncoderWriterTest extends AbstractJsfTestCase {
   private String stringNoSpecialChars = "Hello, this is MyFaces speaking!";
   private String stringNoSpecialCharsEncoded = "Hello, this is MyFaces speaking!";
   private String stringNoSpecialCharsEncodedPartial = "lo, this is MyFaces speakin";
@@ -47,50 +43,64 @@ public class HTMLEncoderTest extends Abs
   private String stringBlanks = "<Hello   this is MyFaces speaking!>";
   private String stringBlanksEncoded = "&lt;Hello   this is MyFaces speaking!&gt";
 
-  public HTMLEncoderTest(String name) {
+  private StringWriter sw;
+  
+  public HTMLEncoderWriterTest(String name) {
     super(name);
   }
 
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        sw = new StringWriter(40);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        sw = null;
+    }
+
   /**
    * Test method for
    * {@link org.apache.myfaces.shared.renderkit.html.util.HTMLEncoder#encode(String)}.
    */
-  public void testEncodeStringNoSpecialChars() {
-    String encodedStr = HTMLEncoder.encode(stringNoSpecialChars);
-    assertEquals(stringNoSpecialCharsEncoded, encodedStr);
+  public void testEncodeStringNoSpecialChars() throws Exception {
+    HTMLEncoder.encode(sw, stringNoSpecialChars);
+    assertEquals(stringNoSpecialCharsEncoded, sw.toString());
   }
 
-  public void testEncodeStringSpecialChars1() {
-    String encodedStr = HTMLEncoder.encode(stringSpecialChars1);
-    assertEquals(stringSpecialChars1Encoded, encodedStr);
+  public void testEncodeStringSpecialChars1() throws Exception {
+    HTMLEncoder.encode(sw, stringSpecialChars1);
+    assertEquals(stringSpecialChars1Encoded, sw.toString());
   }
 
-  public void testEncodeStringSpecialChars2() {
-    String encodedStr = HTMLEncoder.encode(stringSpecialChars2);
-    assertEquals(stringSpecialChars2Encoded, encodedStr);
+  public void testEncodeStringSpecialChars2() throws Exception {
+    HTMLEncoder.encode(sw, stringSpecialChars2);
+    assertEquals(stringSpecialChars2Encoded, sw.toString());
   }
 
-  public void testEncodeStringLineBreak1() {
-    String encodedStr = HTMLEncoder.encode(stringLineBreak, true);
-    assertEquals(stringLineBreakEncoded1, encodedStr);
+  public void testEncodeStringLineBreak1() throws Exception {
+    HTMLEncoder.encode(sw, stringLineBreak, true);
+    assertEquals(stringLineBreakEncoded1, sw.toString());
   }
 
-  public void testEncodeStringLineBreak2() {
-    String encodedStr = HTMLEncoder.encode(stringLineBreak, false);
-    assertEquals(stringLineBreakEncoded2, encodedStr);
+  public void testEncodeStringLineBreak2() throws Exception {
+    HTMLEncoder.encode(sw, stringLineBreak, false);
+    assertEquals(stringLineBreakEncoded2, sw.toString());
   }
 
-  public void testEncodeStringEmpty() {
-    String encodedStr = HTMLEncoder.encode("");
-    assertEquals("", encodedStr);
+  public void testEncodeStringEmpty() throws Exception {
+    HTMLEncoder.encode(sw, "");
+    assertEquals("", sw.toString());
   }
 
-  public void testEncodeStringNull() {
-    String encodedStr = HTMLEncoder.encode(null);
-    assertEquals("", encodedStr);
+  public void testEncodeStringNull() throws Exception {
+    HTMLEncoder.encode(sw, null);
+    assertEquals("", sw.toString());
   }
 
-  public void testEncodeArrayNoSpecialChars() {
+  public void testEncodeArrayNoSpecialChars() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringNoSpecialChars.toCharArray();
@@ -101,7 +111,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayNoSpecialCharsPartial() {
+  public void testEncodeArrayNoSpecialCharsPartial() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringNoSpecialChars.toCharArray();
@@ -112,7 +122,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArraySpecialChars1() {
+  public void testEncodeArraySpecialChars1() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringSpecialChars1.toCharArray();
@@ -123,7 +133,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArraySpecialChars2() {
+  public void testEncodeArraySpecialChars2() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringSpecialChars2.toCharArray();
@@ -134,7 +144,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayEmpty() {
+  public void testEncodeArrayEmpty() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       HTMLEncoder.encode(new char[]{}, 0, 1, writer);
@@ -144,7 +154,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayNull() {
+  public void testEncodeArrayNull() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       HTMLEncoder.encode(null, 0, 0, writer);
@@ -154,7 +164,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayWrongIndex1() {
+  public void testEncodeArrayWrongIndex1() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringSpecialChars2.toCharArray();
@@ -165,7 +175,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayWrongIndex2() {
+  public void testEncodeArrayWrongIndex2() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringSpecialChars2.toCharArray();
@@ -176,7 +186,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayWrongIndex3() {
+  public void testEncodeArrayWrongIndex3() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringSpecialChars2.toCharArray();
@@ -187,7 +197,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayLineBreak1() {
+  public void testEncodeArrayLineBreak1() throws Exception {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringLineBreak.toCharArray();
@@ -198,7 +208,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayLineBreak2() {
+  public void testEncodeArrayLineBreak2() throws Exception  {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringLineBreak.toCharArray();
@@ -209,7 +219,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayLineBreak2WrongIndex() {
+  public void testEncodeArrayLineBreak2WrongIndex() throws Exception  {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringLineBreak.toCharArray();
@@ -220,7 +230,7 @@ public class HTMLEncoderTest extends Abs
     }
   }
 
-  public void testEncodeArrayLineBreakPartial() {
+  public void testEncodeArrayLineBreakPartial() throws Exception  {
     try {
       CharArrayWriter writer = new CharArrayWriter();
       char[] source = stringLineBreak.toCharArray();
@@ -241,11 +251,12 @@ public class HTMLEncoderTest extends Abs
     }
   }
   
-  public void testSimpleWriteURIAttribute() throws Exception
+;  public void testSimpleWriteURIAttribute() throws Exception
   {
       String cad1 = "http://myfaces.apache.org/hello.jsf?key1=val&key2=val2#id";
       String cad2 = "http://myfaces.apache.org/hello.jsf?key1=val&amp;key2=val2#id";
-      String cad3 = HTMLEncoder.encodeURIAtributte(cad1,"UTF-8");
+      HTMLEncoder.encodeURIAtributte(sw, cad1,"UTF-8");
+      String cad3 = sw.toString();
       assertEquals(cad2, cad3);      
   }
   
@@ -260,12 +271,15 @@ public class HTMLEncoderTest extends Abs
       // - From %7F ad infinitum
       String cad1 = "?key=\"%<>\\`{|}^\n "; //Omit %
       String cad2 = "?key=%22%25%3C%3E%5C%60%7B%7C%7D%5E%0A%20";
-      String cad3 = HTMLEncoder.encodeURIAtributte(cad1,"UTF-8");
+      HTMLEncoder.encodeURIAtributte(sw, cad1,"UTF-8");
+      String cad3 = sw.toString();
       assertEquals(cad2, cad3);
       
       String cad4 = "\"%<>\\`{|}^\n ";
       String cad5 = "%22%25%3C%3E%5C%60%7B%7C%7D%5E%0A%20";
-      String cad6 = HTMLEncoder.encodeURIAtributte(cad4,"UTF-8");
+      sw = new StringWriter();
+      HTMLEncoder.encodeURIAtributte(sw, cad4,"UTF-8");
+      String cad6 = sw.toString();
       assertEquals(cad5, cad6);
       
       
@@ -278,7 +292,8 @@ public class HTMLEncoderTest extends Abs
 	  byte [] array = new byte[]{(byte)0xFC};
       String cad1 = new String(array,"ISO-8859-1");//+(char)0xC3BC;//"http://myfaces.apache.org/heüll o.jsf?key=val#id";
       String cad2 = "%C3%BC";//"http://myfaces.apache.org/he%FCll%20o.jsf?key=val#id";
-      String cad3 = HTMLEncoder.encodeURIAtributte(cad1,"UTF-8");
+      HTMLEncoder.encodeURIAtributte(sw, cad1,"UTF-8");
+      String cad3 = sw.toString();
       assertEquals(cad2, cad3);
 
   }
@@ -294,11 +309,14 @@ public class HTMLEncoderTest extends Abs
       //               %21   %24   %26   %27   %28   %29   %2A   %2B   %2C   %3B   %3D
       
       String cad1 = "?key=:/[]@!$'()*+,;="; //Omit &
-      String cad2 = HTMLEncoder.encodeURIAtributte(cad1,"UTF-8");
+      HTMLEncoder.encodeURIAtributte(sw, cad1,"UTF-8");
+      String cad2 = sw.toString();
       assertEquals(cad1, cad2);
       
       String cad7 = ":/[]@!$&'()*+,;=";
-      String cad8 = HTMLEncoder.encodeURIAtributte(cad7,"UTF-8");
+      sw = new StringWriter(40);
+      HTMLEncoder.encodeURIAtributte(sw, cad7,"UTF-8");
+      String cad8 = sw.toString();
       assertEquals(cad7, cad8);
   }
 
@@ -309,15 +327,20 @@ public class HTMLEncoderTest extends Abs
       // underscore (%5F), or tilde (%7E) should not be created by URI
       // producers...."
       String cad1 = "?key=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
-      String cad2 = HTMLEncoder.encodeURIAtributte(cad1,"UTF-8");
+      HTMLEncoder.encodeURIAtributte(sw, cad1,"UTF-8");
+      String cad2 = sw.toString();
       assertEquals(cad1, cad2);
       
       String cad3 = "#somefile?key=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
-      String cad4 = HTMLEncoder.encodeURIAtributte(cad3,"UTF-8");
+      sw = new StringWriter(40);
+      HTMLEncoder.encodeURIAtributte(sw, cad3,"UTF-8");
+      String cad4 = sw.toString();
       assertEquals(cad3, cad4);
       
       String cad5 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
-      String cad6 = HTMLEncoder.encodeURIAtributte(cad5,"UTF-8");
+      sw = new StringWriter(40);
+      HTMLEncoder.encodeURIAtributte(sw, cad5,"UTF-8");
+      String cad6 = sw.toString();
       assertEquals(cad5, cad6);
   }
 
@@ -335,13 +358,16 @@ public class HTMLEncoderTest extends Abs
       String cad11 = new String(array11,"UTF-8") + ((char)(0xFF))+((char)(0x100));
       String cad12 = "%C2%A1%C2%A2%C2%A3%C2%A4%C2%A5%C2%A6%C2%A7%C2%A8%C2%A9%C2%AA%C2%AB%C2%AC%C2%AD"+
                      "%C2%AE%C2%AF%C2%B0%C2%B1%C3%BF%C4%80";
-      String cad13 = HTMLEncoder.encodeURIAtributte(cad11,"UTF-8");
+      HTMLEncoder.encodeURIAtributte(sw, cad11,"UTF-8");
+      String cad13 = sw.toString();
       assertEquals(cad12, cad13);
       
       String cad1= "?key=" + new String(array11,"UTF-8")+((char)(0xFF))+((char)(0x100));
       String cad2 = "?key=%C2%A1%C2%A2%C2%A3%C2%A4%C2%A5%C2%A6%C2%A7%C2%A8%C2%A9%C2%AA%C2%AB%C2%AC%C2%AD"+
                      "%C2%AE%C2%AF%C2%B0%C2%B1%C3%BF%C4%80";
-      String cad3 = HTMLEncoder.encodeURIAtributte(cad1,"UTF-8");
+      sw = new StringWriter(40);
+      HTMLEncoder.encodeURIAtributte(sw, cad1,"UTF-8");
+      String cad3 = sw.toString();
       assertEquals(cad2, cad3);
             
       //String cad14 = "http://myfaces.apache.org/page.jsf?key="+((char)0xFF)+((char)0x100);

Added: myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoderTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoderTest.java?rev=1230285&view=auto
==============================================================================
--- myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoderTest.java (added)
+++ myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoderTest.java Wed Jan 11 22:23:28 2012
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 The Apache Software Foundation.
+ *
+ * Licensed 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.
+ */
+package org.apache.myfaces.shared.renderkit.html.util;
+
+import java.io.StringWriter;
+import junit.framework.Assert;
+import org.apache.myfaces.test.base.junit4.AbstractJsfTestCase;
+import org.junit.Test;
+
+/**
+ *
+ * @author lu4242
+ */
+public class UnicodeEncoderTest extends AbstractJsfTestCase
+{
+
+    @Test
+    public void testUnicodeEncoder1() throws Exception
+    {
+        StringWriter sw = new StringWriter(40);
+        UnicodeEncoder.encode(sw, ""+(char)0xE1);
+        Assert.assertEquals(UnicodeEncoder.encode(""+(char)0xE1), sw.toString());
+    }
+    
+    @Test
+    public void testUnicodeEncoder2() throws Exception
+    {
+        StringWriter sw = new StringWriter(40);
+        UnicodeEncoder.encode(sw, "h"+(char)0xE1);
+        Assert.assertEquals(UnicodeEncoder.encode("h"+(char)0xE1), sw.toString());
+    }
+    
+    @Test
+    public void testUnicodeEncoder3() throws Exception
+    {
+        StringWriter sw = new StringWriter(40);
+        UnicodeEncoder.encode(sw, ""+(char)0xE1+"a");
+        Assert.assertEquals(UnicodeEncoder.encode(""+(char)0xE1)+"a", sw.toString());
+    }
+    
+    @Test
+    public void testUnicodeEncoder4() throws Exception
+    {
+        StringWriter sw = new StringWriter(40);
+        UnicodeEncoder.encode(sw, "hello h"+(char)0xE1+"aaa <p></p>");
+        Assert.assertEquals("hello h&#225;aaa <p></p>", sw.toString());
+    }
+
+}

Propchange: myfaces/core/trunk/shared/src/test/java/org/apache/myfaces/shared/renderkit/html/util/UnicodeEncoderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native