View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.component.html.ext;
20  
21  import javax.faces.FacesException;
22  
23  class _SubIdConverter
24  {
25      private static final String HEX_CHARSET = "0123456789ABCDEF";
26      
27      /**
28       * Encode the string into an html sub id valid value.  
29       * 
30       * An html id must comply with the following rules
31       * 
32       * 1. Must begin with a letter A-Z or a-z
33       * 2. Can be followed by: letters (A-Za-z), digits (0-9), hyphens ("-"), underscores ("_"), colons (":"), and periods (".")
34       * 3. Values are case-sensitive
35       * 
36       * The first rule is warranted because this convert an sub id, so a prefix is always added to
37       * the returning string. The encoder converts all non valid chars into a unicode hex string prefixed with '_' char.
38       * For example _ is converted to _005F, + is converted to _002B and so on.
39       * 
40       * @param string
41       * @param characterEncoding
42       * @return
43       */
44      public static String encode(final String string)
45      {
46          StringBuilder sb = null;    //create later on demand
47          String app;
48          char c;
49          boolean endLoop = false;
50          for (int i = 0; i < string.length (); ++i)
51          {
52              app = null;
53              c = string.charAt(i);
54              
55              if (( c >= '0' && c <='9') || (c >='A' && c <='Z') || (c >='a' && c <='z')
56                  || c == ':' || c == '.' ) //|| c == '-' // '-' used to indicate rowIndex
57              {
58                  //No encoding, just do nothing, char will be added later.
59              }
60              else
61              {
62                  
63                  app = "_" + HEX_CHARSET.charAt( ((c >> 0x0C) % 0x10)) +  HEX_CHARSET.charAt( ((c >> 0x8) % 0x10)) + HEX_CHARSET.charAt( ((c >> 0x4) % 0x10)) +HEX_CHARSET.charAt(c % 0x10);
64              }
65                          
66              if (app != null)
67              {
68                  if (sb == null)
69                  {
70                      sb = new StringBuilder(string.substring(0, i));
71                  }
72                  sb.append(app);
73              } else {
74                  if (sb != null)
75                  {
76                      sb.append(c);
77                  }
78              }
79              if (endLoop)
80              {
81                  break;
82              }
83          }
84          if (sb == null)
85          {
86              return string;
87          }
88          else
89          {
90              return sb.toString();
91          }
92      }
93  
94      public static String decode(final String string)
95      {
96          StringBuilder sb = null;    //create later on demand
97          String app;
98          char c;
99          boolean endLoop = false;
100         for (int i = 0; i < string.length (); ++i)
101         {
102             app = null;
103             c = string.charAt(i);
104             
105             if (c == '_')
106             {
107                 int value = (toDigit(string.charAt(i+1)) << 0x0C) + (toDigit(string.charAt(i+2)) << 0x08) + (toDigit(string.charAt(i+3)) << 0x04) + toDigit(string.charAt(i+4));
108                 
109                 if (sb == null)
110                 {
111                     sb = new StringBuilder(string.substring(0, i));
112                 }
113                 i += 4;
114                 app = ""+((char)value);
115             }
116             else
117             {
118                 //No decoding
119             }
120 
121             if (app != null)
122             {
123                 if (sb == null)
124                 {
125                     sb = new StringBuilder(string.substring(0, i));
126                 }
127                 sb.append(app);
128             } else {
129                 if (sb != null)
130                 {
131                     sb.append(c);
132                 }
133             }
134             if (endLoop)
135             {
136                 break;
137             }
138         }
139         if (sb == null)
140         {
141             return string;
142         }
143         else
144         {
145             return sb.toString();
146         }
147     }
148     
149     /**
150      * Converts a hexadecimal character to an integer.
151      * 
152      * @param ch
153      *            A character to convert to an integer digit
154      * @param index
155      *            The index of the character in the source
156      * @return An integer
157      * @throws DecoderException
158      *             Thrown if ch is an illegal hex character
159      */
160     protected static int toDigit(char ch)
161     {
162         int digit = Character.digit(ch, 16);
163         if (digit == -1)
164         {
165             throw new FacesException("Illegal hexadecimal charcter ");
166         }
167         return digit;
168     }
169 }