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 }