1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package ca.uhn.hl7v2.parser;
28
29 import java.util.Collections;
30 import java.util.LinkedHashMap;
31 import java.util.Map;
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class DefaultEscaping implements Escaping {
46
47
48
49
50 private static final Map<EncodingCharacters, EncLookup> variousEncChars = Collections.synchronizedMap(new LinkedHashMap
51 <EncodingCharacters, EncLookup>(6, 0.75f, true) {
52
53 private static final long serialVersionUID = 1L;
54 final int maxSize = Integer.parseInt(System.getProperty(Escape.class.getName() + ".maxSize", "1000"));
55
56 @Override
57 protected boolean removeEldestEntry(Map.Entry<EncodingCharacters, EncLookup> eldest) {
58 return this.size() > maxSize;
59 }
60 });
61
62
63
64
65
66
67
68 public String escape(String text, EncodingCharacters encChars) {
69 EncLookup esc = getEscapeSequences(encChars);
70 int textLength = text.length();
71
72 StringBuilder result = new StringBuilder(textLength);
73 for (int i = 0; i < textLength; i++) {
74 boolean charReplaced = false;
75 char c = text.charAt(i);
76
77 FORENCCHARS:
78 for (int j = 0; j < esc.characters.length; j++) {
79 if (text.charAt(i) == esc.characters[j]) {
80
81
82 if (j == 4) {
83
84 if (i+1 < textLength) {
85
86
87 char nextChar = text.charAt(i + 1);
88 switch (nextChar) {
89 case '.':
90 case 'C':
91 case 'M':
92 case 'X':
93 case 'Z':
94 {
95 int nextEscapeIndex = text.indexOf(esc.characters[j], i + 1);
96 if (nextEscapeIndex > 0) {
97 result.append(text, i, nextEscapeIndex + 1);
98 charReplaced = true;
99 i = nextEscapeIndex;
100 break FORENCCHARS;
101 }
102 break;
103 }
104 case 'H':
105 case 'N':
106 {
107 if (i+2 < textLength && text.charAt(i+2) == '\\') {
108 int nextEscapeIndex = i + 2;
109 if (nextEscapeIndex > 0) {
110 result.append(text, i, nextEscapeIndex + 1);
111 charReplaced = true;
112 i = nextEscapeIndex;
113 break FORENCCHARS;
114 }
115 }
116 break;
117 }
118 }
119
120 }
121
122 }
123
124 result.append(esc.encodings[j]);
125 charReplaced = true;
126 break;
127 }
128 }
129 if (!charReplaced) {
130 result.append(c);
131 }
132 }
133 return result.toString();
134 }
135
136
137
138
139
140
141 public String unescape(String text, EncodingCharacters encChars) {
142
143
144 char escapeChar = encChars.getEscapeCharacter();
145 boolean foundEscapeChar = false;
146 for (int i = 0; i < text.length(); i++) {
147 if (text.charAt(i) == escapeChar) {
148 foundEscapeChar = true;
149 break;
150 }
151 }
152 if (!foundEscapeChar) {
153 return text;
154 }
155
156 int textLength = text.length();
157 StringBuilder result = new StringBuilder(textLength + 20);
158 EncLookup esc = getEscapeSequences(encChars);
159 char escape = esc.characters[4];
160 int encodingsCount = esc.characters.length;
161 int i = 0;
162 while (i < textLength) {
163 char c = text.charAt(i);
164 if (c != escape) {
165 result.append(c);
166 i++;
167 } else {
168 boolean foundEncoding = false;
169
170
171 for (int j = 0; j < encodingsCount; j++) {
172 String encoding = esc.encodings[j];
173 int encodingLength = encoding.length();
174 if ((i + encodingLength <= textLength) && text.substring(i, i + encodingLength)
175 .equals(encoding)) {
176 result.append(esc.characters[j]);
177 i += encodingLength;
178 foundEncoding = true;
179 break;
180 }
181 }
182
183 if (!foundEncoding) {
184
185
186
187 if (i + 1 < textLength) {
188 char nextChar = text.charAt(i + 1);
189 switch (nextChar) {
190 case '.':
191 case 'C':
192 case 'M':
193 case 'X':
194 case 'Z':
195 {
196 int closingEscape = text.indexOf(escape, i + 1);
197 if (closingEscape > 0) {
198 String substring = text.substring(i, closingEscape + 1);
199 result.append(substring);
200 i += substring.length();
201 } else {
202 i++;
203 }
204 break;
205 }
206 case 'H':
207 case 'N':
208 {
209 int closingEscape = text.indexOf(escape, i + 1);
210 if (closingEscape == i + 2) {
211 String substring = text.substring(i, closingEscape + 1);
212 result.append(substring);
213 i += substring.length();
214 } else {
215 i++;
216 }
217 break;
218 }
219 default:
220 {
221 i++;
222 }
223 }
224
225 } else {
226 i++;
227 }
228 }
229
230
231 }
232 }
233 return result.toString();
234 }
235
236
237
238
239
240 private static EncLookup getEscapeSequences(EncodingCharacters encChars) {
241 EncLookup escapeSequences = variousEncChars.get(encChars);
242 if (escapeSequences == null) {
243
244
245 escapeSequences = new EncLookup(encChars);
246 variousEncChars.put(encChars, escapeSequences);
247 }
248 return escapeSequences;
249 }
250
251
252
253
254
255
256
257
258
259
260
261 private static class EncLookup {
262
263 private static final char[] CODES = {'F', 'S', 'T', 'R', 'E', 'L'};
264 private final char[] characters = new char[7];
265 final String[] encodings = new String[7];
266
267 EncLookup(EncodingCharacters ec) {
268 characters[0] = ec.getFieldSeparator();
269 characters[1] = ec.getComponentSeparator();
270 characters[2] = ec.getSubcomponentSeparator();
271 characters[3] = ec.getRepetitionSeparator();
272 characters[4] = ec.getEscapeCharacter();
273 characters[5] = ec.getTruncationCharacter();
274 characters[6] = '\r';
275
276 for (int i = 0; i < CODES.length; i++) {
277 String seq = String.valueOf(ec.getEscapeCharacter()) +
278 CODES[i] +
279 ec.getEscapeCharacter();
280 encodings[i] = seq;
281 }
282
283
284
285 encodings[5] = "#";
286 encodings[6] = "\\X000d\\";
287 }
288 }
289 }
290