1 package ca.uhn.hl7v2.model.primitive;
2
3 import java.util.regex.Matcher;
4 import java.util.regex.Pattern;
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 public class FormattedTextEncoder {
23
24 private StringBuilder myBuffer;
25 private int myInBold;
26 private boolean myInCenter;
27
28
29
30
31 private FormattedTextEncoder() {
32 super();
33 }
34
35 private void addLt() {
36 myBuffer.append("<");
37 }
38
39 private void addGt() {
40 myBuffer.append(">");
41 }
42
43 private void addAmpersand() {
44 myBuffer.append("&");
45 }
46
47 private void addBreak() {
48 myBuffer.append("<br>");
49 }
50
51 private void addEndNoBreak() {
52 myBuffer.append("</nobr>");
53 }
54
55 private void addHighAscii(char nextChar) {
56 myBuffer.append("&#");
57 myBuffer.append((int) nextChar);
58 myBuffer.append(";");
59 }
60
61 private void addSpace() {
62 myBuffer.append(" ");
63 }
64
65 private void addStartCenter() {
66 myBuffer.append("<center>");
67 }
68
69 private void addStartNoBreak() {
70 myBuffer.append("<nobr>");
71 }
72
73 private void closeCenterIfNeeded() {
74 if (myInCenter) {
75 myBuffer.append("</center>");
76 }
77 }
78
79
80
81
82
83
84
85
86
87 public String encode(String theInput) {
88 if (theInput == null) {
89 return null;
90 }
91
92 myBuffer = new StringBuilder(theInput.length() + 20);
93 boolean myAtStartOfLine = true;
94 myInCenter = false;
95 boolean myWordWrap = true;
96 int myCurrentLineOffset = 0;
97 int myTemporaryIndent = 0;
98 int myIndent = 0;
99 boolean myNeedBreakBeforeNextText = false;
100 boolean myInDiv = false;
101 myInBold = 0;
102
103 for (int i = 0; i < theInput.length(); i++) {
104
105 char nextChar = theInput.charAt(i);
106 boolean handled = true;
107
108 if (nextChar == '\\') {
109 int theStart = i + 1;
110 int numericArgument = Integer.MIN_VALUE;
111 int offsetIncludingNumericArgument = 0;
112 String nextFourChars = theInput.substring(theStart, Math.min(theInput.length(), theStart + 4)).toLowerCase();
113 if (theInput.length() >= theStart + 5) {
114 char sep = theInput.charAt(i + 4);
115 if (theInput.charAt(i + 1) == '.' && (sep == ' ' || sep == '-' || sep == '+')) {
116 String nextThirtyChars = theInput.substring(theStart + 3, Math.min(theInput.length(), theStart + 30));
117 Matcher m = Pattern.compile("^([ +-]?[0-9]+)\\\\").matcher(nextThirtyChars);
118 if (m.find()) {
119 String group = m.group(1);
120 offsetIncludingNumericArgument = group.length() + 4;
121 group = group.replace('+', ' ').trim();
122 numericArgument = Integer.parseInt(group);
123 }
124 }
125 }
126
127 if (nextFourChars.equals(".br\\")) {
128
129 closeCenterIfNeeded();
130 if (myNeedBreakBeforeNextText) {
131 addBreak();
132 }
133 myNeedBreakBeforeNextText = true;
134 i += 4;
135 myAtStartOfLine = true;
136 myInCenter = false;
137 myCurrentLineOffset = 0;
138
139 } else if (nextFourChars.startsWith("h\\")) {
140
141 startBold();
142 i += 2;
143
144 } else if (nextFourChars.startsWith("n\\")) {
145
146 endBold();
147 i += 2;
148
149 } else if (nextFourChars.startsWith(".in") && myAtStartOfLine && numericArgument != Integer.MIN_VALUE) {
150
151 myIndent = numericArgument;
152 myTemporaryIndent = 0;
153 i += offsetIncludingNumericArgument;
154
155 } else if (nextFourChars.startsWith(".ti") && myAtStartOfLine && numericArgument != Integer.MIN_VALUE) {
156
157 myTemporaryIndent = numericArgument;
158 i += offsetIncludingNumericArgument;
159
160 } else if (nextFourChars.equals(".ce\\")) {
161
162 closeCenterIfNeeded();
163 if (!myAtStartOfLine) {
164 addBreak();
165 }
166 addStartCenter();
167 i += 4;
168 myAtStartOfLine = false;
169 myInCenter = true;
170
171 } else if (nextFourChars.equals(".fi\\")) {
172
173 if (!myWordWrap) {
174 addEndNoBreak();
175 myWordWrap = true;
176 }
177 i += 4;
178
179 } else if (nextFourChars.equals(".nf\\")) {
180
181 if (myWordWrap) {
182 addStartNoBreak();
183 myWordWrap = false;
184 }
185 i += 4;
186
187 } else if (nextFourChars.startsWith(".sp")) {
188
189 if (nextFourChars.equals(".sp\\")) {
190 numericArgument = 1;
191 i += 4;
192 } else if (numericArgument != -1) {
193 i += offsetIncludingNumericArgument;
194 }
195
196 if (numericArgument > 0) {
197
198 for (int j = 0; j < numericArgument; j++) {
199 addBreak();
200 }
201 for (int j = 0; j < myCurrentLineOffset; j++) {
202 addSpace();
203 }
204
205 } else if (numericArgument == Integer.MIN_VALUE) {
206
207 handled = false;
208
209 }
210
211 } else if (nextFourChars.equals(".sk ") && numericArgument >= 0) {
212
213 for (int j = 0; j < numericArgument; j++) {
214 addSpace();
215 }
216 i += offsetIncludingNumericArgument;
217
218 } else {
219
220 handled = false;
221
222 }
223 } else {
224 handled = false;
225 }
226
227 if (!handled) {
228
229 if (myAtStartOfLine) {
230
231 int thisLineIndent = Math.max(0, myIndent + myTemporaryIndent);
232 if (myNeedBreakBeforeNextText) {
233
234 if (myInDiv) {
235 myBuffer.append("</div>");
236 } else if (thisLineIndent == 0) {
237 addBreak();
238 }
239 }
240
241 if (thisLineIndent > 0) {
242 myBuffer.append("<div style=\"margin-left: ");
243 myBuffer.append(thisLineIndent);
244 myBuffer.append("em;\">");
245 myInDiv = true;
246 }
247 }
248
249 switch (nextChar) {
250 case '&':
251 addAmpersand();
252 break;
253 case '<':
254 addLt();
255 break;
256 case '>':
257 addGt();
258 break;
259 default:
260 if (nextChar >= 160) {
261 addHighAscii(nextChar);
262 } else {
263 myBuffer.append(nextChar);
264 }
265 }
266
267 myAtStartOfLine = false;
268 myNeedBreakBeforeNextText = false;
269 myCurrentLineOffset++;
270
271 }
272
273 }
274
275 endBold();
276
277 if (!myWordWrap) {
278 addEndNoBreak();
279 }
280 closeCenterIfNeeded();
281
282 if (myInDiv) {
283 myBuffer.append("</div>");
284 }
285
286 return myBuffer.toString();
287 }
288
289 private void endBold() {
290 for (int i = 0; i < myInBold; i++) {
291 myBuffer.append("</b>");
292 }
293 myInBold = 0;
294 }
295
296 private void startBold() {
297 myBuffer.append("<b>");
298 myInBold++;
299 }
300
301
302
303
304
305
306
307
308
309 public static FormattedTextEncoder getInstanceHtml() {
310 return new FormattedTextEncoder();
311 }
312
313 }