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 import java.lang.StringBuffer;
23
24 class _SubIdConverter
25 {
26 private static final String HEX_CHARSET = "0123456789ABCDEF";
27
28 /**
29 * Encode the string into an html sub id valid value.
30 *
31 * An html id must comply with the following rules
32 *
33 * 1. Must begin with a letter A-Z or a-z
34 * 2. Can be followed by: letters (A-Za-z), digits (0-9), hyphens ("-"), underscores ("_"), colons (":"), and periods (".")
35 * 3. Values are case-sensitive
36 *
37 * The first rule is warranted because this convert an sub id, so a prefix is always added to
38 * the returning string. The encoder converts all non valid chars into a unicode hex string prefixed with '_' char.
39 * For example _ is converted to _005F, + is converted to _002B and so on.
40 *
41 * @param string
42 * @param characterEncoding
43 * @return
44 */
45 public static String encode(final String string)
46 {
47 StringBuffer sb = null; //create later on demand
48 String app;
49 char c;
50 boolean endLoop = false;
51 for (int i = 0; i < string.length (); ++i)
52 {
53 app = null;
54 c = string.charAt(i);
55
56 if (( c >= '0' && c <='9') || (c >='A' && c <='Z') || (c >='a' && c <='z')
57 || c == ':' || c == '.' ) //|| c == '-' // '-' used to indicate rowIndex
58 {
59 //No encoding, just do nothing, char will be added later.
60 }
61 else
62 {
63
64 app = "_" + HEX_CHARSET.charAt( ((c >> 0x0C) % 0x10)) + HEX_CHARSET.charAt( ((c >> 0x8) % 0x10)) + HEX_CHARSET.charAt( ((c >> 0x4) % 0x10)) +HEX_CHARSET.charAt(c % 0x10);
65 }
66
67 if (app != null)
68 {
69 if (sb == null)
70 {
71 sb = new StringBuffer(string.substring(0, i));
72 }
73 sb.append(app);
74 } else {
75 if (sb != null)
76 {
77 sb.append(c);
78 }
79 }
80 if (endLoop)
81 {
82 break;
83 }
84 }
85 if (sb == null)
86 {
87 return string;
88 }
89 else
90 {
91 return sb.toString();
92 }
93 }
94
95 public static String decode(final String string)
96 {
97 StringBuffer sb = null; //create later on demand
98 String app;
99 char c;
100 boolean endLoop = false;
101 for (int i = 0; i < string.length (); ++i)
102 {
103 app = null;
104 c = string.charAt(i);
105
106 if (c == '_')
107 {
108 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));
109
110 if (sb == null)
111 {
112 sb = new StringBuffer(string.substring(0, i));
113 }
114 i += 4;
115 app = ""+((char)value);
116 }
117 else
118 {
119 //No decoding
120 }
121
122 if (app != null)
123 {
124 if (sb == null)
125 {
126 sb = new StringBuffer(string.substring(0, i));
127 }
128 sb.append(app);
129 } else {
130 if (sb != null)
131 {
132 sb.append(c);
133 }
134 }
135 if (endLoop)
136 {
137 break;
138 }
139 }
140 if (sb == null)
141 {
142 return string;
143 }
144 else
145 {
146 return sb.toString();
147 }
148 }
149
150 /**
151 * Converts a hexadecimal character to an integer.
152 *
153 * @param ch
154 * A character to convert to an integer digit
155 * @param index
156 * The index of the character in the source
157 * @return An integer
158 * @throws DecoderException
159 * Thrown if ch is an illegal hex character
160 */
161 protected static int toDigit(char ch)
162 {
163 int digit = Character.digit(ch, 16);
164 if (digit == -1)
165 {
166 throw new FacesException("Illegal hexadecimal charcter ");
167 }
168 return digit;
169 }
170 }