View Javadoc

1   /*
2    * $Id: URLFormCodec.java,v 1.18 2011/06/16 09:29:40 jbmeslin Exp $
3    * 
4    */
5   package org.rcfaces.core.internal.codec;
6   
7   import java.io.IOException;
8   import java.io.UnsupportedEncodingException;
9   import java.net.URLDecoder;
10  import java.net.URLEncoder;
11  import java.util.BitSet;
12  
13  import javax.faces.FacesException;
14  import javax.servlet.jsp.JspWriter;
15  
16  import org.rcfaces.core.internal.lang.StringAppender;
17  
18  /**
19   * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
20   * @version $Revision: 1.18 $ $Date: 2011/06/16 09:29:40 $
21   */
22  public final class URLFormCodec {
23  
24      private static final String REVISION = "$Revision: 1.18 $";
25  
26      private static final String FORM_DECODER_INPUT_CHARSET = "UTF8";
27  
28      private static final String FORM_DECODER_UTF8_CHARSET = "UTF8";
29  
30      private static final int CASE_DIFF = 'a' - 'A';
31  
32      private static final BitSet dontNeedEncoding;
33      static {
34          dontNeedEncoding = new BitSet(127);
35          int i;
36          for (i = 'a'; i <= 'z'; i++) {
37              dontNeedEncoding.set(i);
38          }
39          for (i = 'A'; i <= 'Z'; i++) {
40              dontNeedEncoding.set(i);
41          }
42          for (i = '0'; i <= '9'; i++) {
43              dontNeedEncoding.set(i);
44          }
45          dontNeedEncoding.set('-');
46          dontNeedEncoding.set('_');
47          dontNeedEncoding.set('.');
48          dontNeedEncoding.set('*');
49      }
50  
51      private static final BitSet urlDontNeedEncoding;
52      static {
53          urlDontNeedEncoding = new BitSet(127);
54          urlDontNeedEncoding.or(dontNeedEncoding);
55  
56          // Pour transformer l'URL sans transformer le sens :-)
57          urlDontNeedEncoding.set('/');
58          urlDontNeedEncoding.set(':');
59          urlDontNeedEncoding.set('?');
60          urlDontNeedEncoding.set('#');
61      }
62  
63      public static String decodeUTF8(String source) {
64          if (source == null) {
65              return null;
66          }
67  
68          int length = source.length();
69          if (length < 3) {
70              return source;
71          }
72  
73          try {
74              return URLDecoder.decode(source, FORM_DECODER_INPUT_CHARSET);
75  
76          } catch (UnsupportedEncodingException e) {
77              throw new FacesException("Can not decode '" + source + "'.", e);
78          }
79  
80          /*
81           * byte buf[]; try { buf = source.getBytes(FORM_DECODER_INPUT_CHARSET); }
82           * catch (UnsupportedEncodingException e) { throw new
83           * FacesException("Unknown charset '" + FORM_DECODER_INPUT_CHARSET +
84           * "'.", e); }
85           * 
86           * int pos = 0;
87           * 
88           * for (int i = 0; i < length; i++) { byte c = buf[i];
89           * 
90           * if (c != '%') { buf[pos++] = c; continue; }
91           * 
92           * if (i + 2 >= length) { // Bad format break; }
93           * 
94           * buf[pos++] = (byte) Integer.parseInt( source.substring(i + 1, i + 3),
95           * 16); i += 2; }
96           * 
97           * try { return new String(buf, 0, pos, FORM_DECODER_UTF8_CHARSET); }
98           * catch (UnsupportedEncodingException e) { throw new
99           * FacesException("Unknown charset '" + FORM_DECODER_UTF8_CHARSET +
100          * "'.", e); }
101          */
102     }
103 
104     private static void append(StringAppender sb, String url, BitSet bitSet,
105             boolean convertSpace) {
106         char chs[] = url.toCharArray();
107 
108         for (int i = 0; i < chs.length; i++) {
109             int c = chs[i];
110 
111             if (c < 256 && bitSet.get(c)) {
112                 sb.append((char) c);
113                 continue;
114             }
115             if (c == 32 && convertSpace) {
116                 sb.append('+');
117                 continue;
118             }
119 
120             // L'espace est transformé ... comme les autres !
121 
122             if (c < 128) {
123                 sb.append('%');
124                 char ch = Character.forDigit((c >> 4) & 0xF, 16);
125                 if (Character.isLetter(ch)) {
126                     ch -= CASE_DIFF;
127                 }
128                 sb.append(ch);
129                 ch = Character.forDigit(c & 0xF, 16);
130                 if (Character.isLetter(ch)) {
131                     ch -= CASE_DIFF;
132                 }
133                 sb.append(ch);
134 
135                 continue;
136             }
137 
138             String form;
139             try {
140                 form = URLEncoder.encode(url.substring(i, i + 1),
141                         FORM_DECODER_UTF8_CHARSET);
142 
143             } catch (UnsupportedEncodingException e) {
144                 throw new FacesException("Can not encode '" + url + "'.", e);
145             }
146             sb.append(form);
147 
148         }
149     }
150 
151     public static void main(String args[]) {
152         System.out.println("DecodeUTF8: '" + args[0] + "' => '"
153                 + decodeUTF8(args[0]) + "'");
154     }
155 
156     public static void writeURL(JspWriter writer, String url)
157             throws IOException {
158         int length = url.length();
159         StringAppender sa = new StringAppender(length * 3 / 2);
160 
161         appendURL(sa, url);
162 
163         sa.copyInto(writer);
164     }
165 
166     public static String decodeURL(String url) {
167         char chs[] = url.toCharArray();
168 
169         return decodeURL(chs, 0, chs.length);
170     }
171 
172     public static String decodeURL(char chs[], int offset, int end) {
173         if (false) {
174             StringAppender sa = new StringAppender(end - offset);
175 
176             next_char: for (; offset < end; offset++) {
177                 int c = chs[offset];
178                 if (c != '%') {
179                     sa.append((char) c);
180                     continue;
181                 }
182 
183                 int v = 0;
184                 for (int j = 0; j < 2; j++) {
185                     offset++;
186                     if (offset >= end) {
187                         break next_char;
188                     }
189 
190                     v <<= 4;
191                     c = chs[offset];
192                     if (c >= '0' && c <= '9') {
193                         v |= (c - '0');
194 
195                     } else if (c >= 'A' && c <= 'F') {
196                         v |= (c - 'A' + 10);
197 
198                     } else if (c >= 'a' && c <= 'f') {
199                         v |= (c - 'a' + 10);
200                     } else {
201                         throw new IllegalStateException(
202                                 "Invalid hexadecimal character " + v);
203                     }
204                 }
205 
206                 sa.append((char) v);
207             }
208 
209             return sa.toString();
210         }
211 
212         return decodeUTF8(new String(chs, offset, end - offset));
213     }
214 
215     public static void appendURL(StringAppender sa, String url) {
216         append(sa, url, urlDontNeedEncoding, false);
217     }
218 
219     public static void encode(StringAppender sa, String value) {
220         append(sa, value, dontNeedEncoding, true);
221     }
222 }