1 package com.atlassian.refapp.sal.pluginsettings;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 /**
7 * This class helps substitute characters that are not supported in xml (see all the chars defined in escapeString variable) to escaped format.
8 * Its implementation is based on $FISHEYE_TRUNK/src/java/com/cenqua/fisheye/util/XmlUtils.java.
9 *
10 * @since 2.7.0
11 */
12 public class XmlUtils {
13
14 private static final char ESCAPE_SYM1 = '!';
15 private static final char ESCAPE_SYM2 = '@';
16 private static final char ESCAPE_SYM3 = '#';
17 private static final char ESCAPE_SYM4 = '$';
18 private static final Map<Character, String> charToCode;
19
20 static {
21 final String escapeString = "\u0000\u0001\u0002\u0003\u0004\u0005" +
22 "\u0006\u0007\u0008\u000B\u000C\u000E\u000F\u0010\u0011\u0012" +
23 "\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C" +
24 "\u001D\u001E\u001F\uFFFE\uFFFF";
25
26 charToCode = new HashMap<Character, String>();
27
28 for (int i = 0; i < escapeString.length(); i++) {
29 final char c = escapeString.charAt(i);
30 charToCode.put(c, "" + ESCAPE_SYM1 + ESCAPE_SYM2
31 + ESCAPE_SYM3 + ESCAPE_SYM4
32 + String.format("%04X", (int) c));
33 }
34 }
35
36 // Not for instantiation.
37 private XmlUtils() {
38 }
39
40 /**
41 * Replaces all characters that are illegal in XML with a custom-made unicode escape sequence.
42 * escape sequence '!@#$[0-9][0-9][0-9][0-9]'. When <code>null</code> is
43 * passed into this method, <code>null</code> is returned.
44 */
45 public static String escape(String string) {
46 if (string == null) {
47 return null;
48 }
49
50 // working buffer.
51 StringBuilder copy = new StringBuilder();
52
53 // just consider every char for a chance of escaping.
54 for (int i = 0; i < string.length(); i++) {
55 copy.append(escapeChar(string.charAt(i)));
56 }
57 return copy.toString();
58 }
59
60 private static String escapeChar(char c) {
61 String escaped = charToCode.get(c);
62 // escape the char if its escape sequence is defined.
63 return escaped == null ? String.valueOf(c) : escaped;
64 }
65
66 /**
67 * Substitutes all occurances of '!@#$[0-9][0-9][0-9][0-9]' with their
68 * corresponding character codes. When <code>null</code> is passed into this
69 * method, <code>null</code> is returned.
70 */
71 public static String unescape(String string) {
72
73 if (string == null) {
74 return null;
75
76 } else {
77
78 // the conversion buffer.
79 final StringBuilder copy = new StringBuilder();
80
81 for (int i = 0; i < string.length(); i++) {
82 char c = string.charAt(i);
83 // if there is a possibility that this is an escape sequence (subject to the parsability of the code part).
84 if (i + 7 < string.length()
85 && c == ESCAPE_SYM1
86 && string.charAt(i + 1) == ESCAPE_SYM2
87 && string.charAt(i + 2) == ESCAPE_SYM3
88 && string.charAt(i + 3) == ESCAPE_SYM4) {
89 // extract the number code
90 String value = string.substring(i + 4, i + 8);
91 try {
92 // if this is parsable fine, we just convert it to the original.
93 int charCode = Integer.parseInt(value, 16);
94 copy.append((char) charCode);
95 i += 7;
96 } catch (NumberFormatException nfe) {
97 // if it cannot be parsed to base 16, then this is not an escape sequence
98 // we simply append the char being read to the buffer.
99 copy.append(c);
100 }
101 }
102 // otherwise, just append the char we just read to the buffer.
103 else {
104 copy.append(c);
105 }
106 }
107
108 return copy.toString();
109 }
110 }
111 }
112