]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/ui/org/eclipse/jdt/internal/ui/propertiesfileeditor/PropertiesFileEscapes.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / ui / org / eclipse / jdt / internal / ui / propertiesfileeditor / PropertiesFileEscapes.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2010 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.ui.propertiesfileeditor;
12
13import org.eclipse.core.runtime.CoreException;
14import org.eclipse.core.runtime.IStatus;
15
16import org.eclipse.jdt.internal.corext.util.Messages;
17
18import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
19
20/**
21 * Helper class to convert between Java chars and the escaped form that must be used in .properties
22 * files.
23 *
24 * @since 3.7
25 */
26public class PropertiesFileEscapes {
27
28 private static final char[] HEX_DIGITS= { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
29
30 private static char toHex(int halfByte) {
31 return HEX_DIGITS[(halfByte & 0xF)];
32 }
33
34 /**
35 * Returns the decimal value of the Hex digit, or -1 if the digit is not a valid Hex digit.
36 *
37 * @param digit the Hex digit
38 * @return the decimal value of digit, or -1 if digit is not a valid Hex digit.
39 */
40 private static int getHexDigitValue(char digit) {
41 switch (digit) {
42 case '0':
43 case '1':
44 case '2':
45 case '3':
46 case '4':
47 case '5':
48 case '6':
49 case '7':
50 case '8':
51 case '9':
52 return digit - '0';
53 case 'a':
54 case 'b':
55 case 'c':
56 case 'd':
57 case 'e':
58 case 'f':
59 return 10 + digit - 'a';
60 case 'A':
61 case 'B':
62 case 'C':
63 case 'D':
64 case 'E':
65 case 'F':
66 return 10 + digit - 'A';
67 default:
68 return -1;
69 }
70 }
71
72 /**
73 * Convert a Java char to the escaped form that must be used in .properties files.
74 *
75 * @param c the Java char
76 * @return escaped string
77 */
78 public static String escape(char c) {
79 return escape(c, true, true, true);
80 }
81
82 /**
83 * Convert characters in a Java string to the escaped form that must be used in .properties
84 * files.
85 *
86 * @param s the Java string
87 * @param escapeWhitespaceChars if <code>true</code>, escape whitespace characters
88 * @param escapeBackslash if <code>true</code>, escape backslash characters
89 * @param escapeUnicodeChars if <code>true</code>, escape unicode characters
90 * @return escaped string
91 */
92 public static String escape(String s, boolean escapeWhitespaceChars, boolean escapeBackslash, boolean escapeUnicodeChars) {
93 StringBuffer sb= new StringBuffer(s.length());
94 int length= s.length();
95 for (int i= 0; i < length; i++) {
96 char c= s.charAt(i);
97 sb.append(escape(c, escapeWhitespaceChars, escapeBackslash, escapeUnicodeChars));
98 }
99 return sb.toString();
100 }
101
102 /**
103 * Convert a Java char to the escaped form that must be used in .properties files.
104 *
105 * @param c the Java char
106 * @param escapeWhitespaceChars if <code>true</code>, escape whitespace characters
107 * @param escapeBackslash if <code>true</code>, escape backslash characters
108 * @param escapeUnicodeChars if <code>true</code>, escape unicode characters
109 * @return escaped string
110 */
111 public static String escape(char c, boolean escapeWhitespaceChars, boolean escapeBackslash, boolean escapeUnicodeChars) {
112 switch (c) {
113 case '\t':
114 return escapeWhitespaceChars ? "\\t" : "\t"; //$NON-NLS-1$//$NON-NLS-2$
115 case '\n':
116 return escapeWhitespaceChars ? "\\n" : "\n"; //$NON-NLS-1$//$NON-NLS-2$
117 case '\f':
118 return escapeWhitespaceChars ? "\\f" : "\r"; //$NON-NLS-1$//$NON-NLS-2$
119 case '\r':
120 return escapeWhitespaceChars ? "\\r" : "\r"; //$NON-NLS-1$//$NON-NLS-2$
121 case '\\':
122 return escapeBackslash ? "\\\\" : "\\"; //$NON-NLS-1$ //$NON-NLS-2$
123 default:
124 if (escapeUnicodeChars && ((c < 0x0020) || (c > 0x007e && c <= 0x00a0) || (c > 0x00ff))) {
125 //NBSP (0x00a0) is escaped to differentiate from normal space character
126 return new StringBuffer()
127 .append('\\')
128 .append('u')
129 .append(toHex((c >> 12) & 0xF))
130 .append(toHex((c >> 8) & 0xF))
131 .append(toHex((c >> 4) & 0xF))
132 .append(toHex(c & 0xF)).toString();
133
134 } else
135 return String.valueOf(c);
136 }
137 }
138
139 /**
140 * Convert an escaped string to a string composed of Java characters.
141 *
142 * @param s the escaped string
143 * @return string composed of Java characters
144 * @throws CoreException if the escaped string has a malformed \\uxxx sequence
145 */
146 public static String unescape(String s) throws CoreException {
147 boolean isValidEscapedString= true;
148 if (s == null)
149 return null;
150
151 char aChar;
152 int len= s.length();
153 StringBuffer outBuffer= new StringBuffer(len);
154
155 for (int x= 0; x < len;) {
156 aChar= s.charAt(x++);
157 if (aChar == '\\') {
158 if (x > len - 1) {
159 return outBuffer.toString(); // silently ignore the \
160 }
161 aChar= s.charAt(x++);
162 if (aChar == 'u') {
163 // Read the xxxx
164 int value= 0;
165 if (x > len - 4) {
166 String exceptionMessage= Messages.format(PropertiesFileEditorMessages.PropertiesFileHover_MalformedEncoding, outBuffer.toString() + s.substring(x - 2));
167 throw new CoreException(new StatusInfo(IStatus.WARNING, exceptionMessage));
168 }
169 StringBuffer buf= new StringBuffer("\\u"); //$NON-NLS-1$
170 int digit= 0;
171 for (int i= 0; i < 4; i++) {
172 aChar= s.charAt(x++);
173 digit= getHexDigitValue(aChar);
174 if (digit == -1) {
175 isValidEscapedString= false;
176 x--;
177 break;
178 }
179 value= (value << 4) + digit;
180 buf.append(aChar);
181 }
182 outBuffer.append(digit == -1 ? buf.toString() : String.valueOf((char)value));
183 } else if (aChar == 't') {
184 outBuffer.append('\t');
185 } else if (aChar == 'n') {
186 outBuffer.append('\n');
187 } else if (aChar == 'f') {
188 outBuffer.append('\f');
189 } else if (aChar == 'r') {
190 outBuffer.append('\r');
191 } else {
192 outBuffer.append(aChar); // silently ignore the \
193 }
194 } else
195 outBuffer.append(aChar);
196 }
197 if (isValidEscapedString) {
198 return outBuffer.toString();
199 } else {
200 String exceptionMessage= Messages.format(PropertiesFileEditorMessages.PropertiesFileHover_MalformedEncoding, outBuffer.toString());
201 throw new CoreException(new StatusInfo(IStatus.WARNING, exceptionMessage));
202 }
203 }
204
205 /**
206 * Unescape backslash characters in a string.
207 *
208 * @param s the escaped string
209 * @return string with backslash characters unescaped
210 */
211 public static String unescapeBackslashes(String s) {
212 if (s == null)
213 return null;
214
215 char c;
216 int length= s.length();
217 StringBuffer outBuffer= new StringBuffer(length);
218
219 for (int i= 0; i < length;) {
220 c= s.charAt(i++);
221 if (c == '\\') {
222 c= s.charAt(i++);
223 }
224 outBuffer.append(c);
225 }
226
227 return outBuffer.toString();
228 }
229
230 /**
231 * Tests if the given text contains any invalid escape sequence.
232 *
233 * @param text the text
234 * @return <code>true</code> if text contains an invalid escape sequence, <code>false</code>
235 * otherwise
236 */
237 public static boolean containsInvalidEscapeSequence(String text) {
238 try {
239 //check for invalid unicode escapes
240 unescape(text);
241 } catch (CoreException e) {
242 return true;
243 }
244
245 int length= text.length();
246 for (int i= 0; i < length; i++) {
247 char c= text.charAt(i);
248 if (c == '\\') {
249 if (i < length - 1) {
250 char nextC= text.charAt(i + 1);
251 switch (nextC) {
252 case 't':
253 case 'n':
254 case 'f':
255 case 'r':
256 case 'u':
257 case '\n':
258 case '\r':
259 case '=':
260 case ':':
261 break;
262 case '\\':
263 i++;
264 break;
265 default:
266 return true;
267 }
268 } else {
269 return true;
270 }
271 }
272 }
273 return false;
274 }
275
276 /**
277 * Tests if the given text contains an unescaped backslash character.
278 *
279 * @param text the text
280 * @return <code>true</code> if text contains an unescaped backslash character,
281 * <code>false</code> otherwise
282 */
283 public static boolean containsUnescapedBackslash(String text) {
284 int length= text.length();
285 for (int i= 0; i < length; i++) {
286 char c= text.charAt(i);
287 if (c == '\\') {
288 if (i < length - 1) {
289 char nextC= text.charAt(i + 1);
290 switch (nextC) {
291 case '\\':
292 i++;
293 break;
294 default:
295 return true;
296 }
297 } else {
298 return true;
299 }
300 }
301 }
302 return false;
303 }
304
305 /**
306 * Tests if the given text contains only escaped backslash characters and no unescaped backslash
307 * character.
308 *
309 * @param text the text
310 * @return <code>true</code> if text contains only escaped backslash characters,
311 * <code>false</code> otherwise
312 */
313 public static boolean containsEscapedBackslashes(String text) {
314 boolean result= false;
315 int length= text.length();
316 for (int i= 0; i < length; i++) {
317 char c= text.charAt(i);
318 if (c == '\\') {
319 if (i < length - 1) {
320 char nextC= text.charAt(i + 1);
321 switch (nextC) {
322 case '\\':
323 i++;
324 result= true;
325 break;
326 default:
327 return false;
328 }
329 } else {
330 return false;
331 }
332 }
333 }
334 return result;
335 }
336}