1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.ini4j.spi;
17
18 import org.ini4j.Registry;
19
20 import org.ini4j.Registry.Type;
21
22 import java.io.UnsupportedEncodingException;
23
24 import java.nio.charset.Charset;
25
26 import java.util.Arrays;
27
28 public class RegEscapeTool extends EscapeTool
29 {
30 private static final RegEscapeTool INSTANCE = ServiceFinder.findService(RegEscapeTool.class);
31 private static final Charset HEX_CHARSET = Charset.forName("UTF-16LE");
32 private static final int LOWER_DIGIT = 0x0f;
33 private static final int UPPER_DIGIT = 0xf0;
34 private static final int DIGIT_SIZE = 4;
35
36 public static final RegEscapeTool getInstance()
37 {
38 return INSTANCE;
39 }
40
41 public TypeValuesPair decode(String raw)
42 {
43 Type type = type(raw);
44 String value = (type == Type.REG_SZ) ? unquote(raw) : raw.substring(type.toString().length() + 1);
45 String[] values;
46
47 switch (type)
48 {
49
50 case REG_EXPAND_SZ:
51 case REG_MULTI_SZ:
52 value = bytes2string(binary(value));
53 break;
54
55 case REG_DWORD:
56 value = String.valueOf(Long.parseLong(value, HEX_RADIX));
57 break;
58
59 case REG_SZ:
60 break;
61
62 default:
63 break;
64 }
65
66 if (type == Type.REG_MULTI_SZ)
67 {
68 values = splitMulti(value);
69 }
70 else
71 {
72 values = new String[] { value };
73 }
74
75 return new TypeValuesPair(type, values);
76 }
77
78 public String encode(TypeValuesPair data)
79 {
80 String ret = null;
81
82 if (data.getType() == Type.REG_SZ)
83 {
84 ret = quote(data.getValues()[0]);
85 }
86 else if (data.getValues()[0] != null)
87 {
88 ret = encode(data.getType(), data.getValues());
89 }
90
91 return ret;
92 }
93
94 byte[] binary(String value)
95 {
96 byte[] bytes = new byte[value.length()];
97 int idx = 0;
98 int shift = DIGIT_SIZE;
99
100 for (int i = 0; i < value.length(); i++)
101 {
102 char c = value.charAt(i);
103
104 if (Character.isWhitespace(c))
105 {
106 continue;
107 }
108
109 if (c == ',')
110 {
111 idx++;
112 shift = DIGIT_SIZE;
113 }
114 else
115 {
116 int digit = Character.digit(c, HEX_RADIX);
117
118 if (digit >= 0)
119 {
120 bytes[idx] |= digit << shift;
121 shift = 0;
122 }
123 }
124 }
125
126 return Arrays.copyOfRange(bytes, 0, idx + 1);
127 }
128
129 String encode(Type type, String[] values)
130 {
131 StringBuilder buff = new StringBuilder();
132
133 buff.append(type.toString());
134 buff.append(Type.SEPARATOR_CHAR);
135 switch (type)
136 {
137
138 case REG_EXPAND_SZ:
139 buff.append(hexadecimal(values[0]));
140 break;
141
142 case REG_DWORD:
143 buff.append(String.format("%08x", Long.parseLong(values[0])));
144 break;
145
146 case REG_MULTI_SZ:
147 int n = values.length;
148
149 for (int i = 0; i < n; i++)
150 {
151 buff.append(hexadecimal(values[i]));
152 buff.append(',');
153 }
154
155 buff.append("00,00");
156 break;
157
158 default:
159 buff.append(values[0]);
160 break;
161 }
162
163 return buff.toString();
164 }
165
166 String hexadecimal(String value)
167 {
168 StringBuilder buff = new StringBuilder();
169
170 if ((value != null) && (value.length() != 0))
171 {
172 byte[] bytes = string2bytes(value);
173
174 for (int i = 0; i < bytes.length; i++)
175 {
176 buff.append(Character.forDigit((bytes[i] & UPPER_DIGIT) >> DIGIT_SIZE, HEX_RADIX));
177 buff.append(Character.forDigit(bytes[i] & LOWER_DIGIT, HEX_RADIX));
178 buff.append(',');
179 }
180
181 buff.append("00,00");
182 }
183
184 return buff.toString();
185 }
186
187 Registry.Type type(String raw)
188 {
189 Registry.Type type;
190
191 if (raw.charAt(0) == DOUBLE_QUOTE)
192 {
193 type = Registry.Type.REG_SZ;
194 }
195 else
196 {
197 int idx = raw.indexOf(Registry.TYPE_SEPARATOR);
198
199 type = (idx < 0) ? Registry.Type.REG_SZ : Registry.Type.fromString(raw.substring(0, idx));
200 }
201
202 return type;
203 }
204
205
206 private String bytes2string(byte[] bytes)
207 {
208 String str;
209
210 try
211 {
212 str = new String(bytes, 0, bytes.length - 2, HEX_CHARSET);
213 }
214 catch (NoSuchMethodError x)
215 {
216 try
217 {
218 str = new String(bytes, 0, bytes.length, HEX_CHARSET.name());
219 }
220 catch (UnsupportedEncodingException ex)
221 {
222 throw new IllegalStateException(ex);
223 }
224 }
225
226 return str;
227 }
228
229 private String[] splitMulti(String value)
230 {
231 int len = value.length();
232 int start;
233 int end;
234 int n = 0;
235
236 start = 0;
237 for (end = value.indexOf(0, start); end >= 0; end = value.indexOf(0, start))
238 {
239 n++;
240 start = end + 1;
241 if (start >= len)
242 {
243 break;
244 }
245 }
246
247 String[] values = new String[n];
248
249 start = 0;
250 for (int i = 0; i < n; i++)
251 {
252 end = value.indexOf(0, start);
253 values[i] = value.substring(start, end);
254 start = end + 1;
255 }
256
257 return values;
258 }
259
260
261 private byte[] string2bytes(String value)
262 {
263 byte[] bytes;
264
265 try
266 {
267 bytes = value.getBytes(HEX_CHARSET);
268 }
269 catch (NoSuchMethodError x)
270 {
271 try
272 {
273 bytes = value.getBytes(HEX_CHARSET.name());
274 }
275 catch (UnsupportedEncodingException ex)
276 {
277 throw new IllegalStateException(ex);
278 }
279 }
280
281 return bytes;
282 }
283 }