1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.yaml.snakeyaml.representer;
18
19 import java.math.BigInteger;
20 import java.util.Arrays;
21 import java.util.Calendar;
22 import java.util.Date;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.TimeZone;
30 import java.util.regex.Pattern;
31
32 import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
33 import org.yaml.snakeyaml.nodes.Node;
34 import org.yaml.snakeyaml.nodes.Tag;
35
36
37
38
39 class SafeRepresenter extends BaseRepresenter {
40
41 protected Map<Class<? extends Object>, Tag> classTags;
42
43 public SafeRepresenter() {
44 this.nullRepresenter = new RepresentNull();
45 this.representers.put(String.class, new RepresentString());
46 this.representers.put(Boolean.class, new RepresentBoolean());
47 this.representers.put(Character.class, new RepresentString());
48 this.representers.put(byte[].class, new RepresentByteArray());
49 this.multiRepresenters.put(Number.class, new RepresentNumber());
50 this.multiRepresenters.put(List.class, new RepresentList());
51 this.multiRepresenters.put(Map.class, new RepresentMap());
52 this.multiRepresenters.put(Set.class, new RepresentSet());
53 this.multiRepresenters.put(Iterator.class, new RepresentIterator());
54 this.multiRepresenters.put(new Object[0].getClass(), new RepresentArray());
55 this.multiRepresenters.put(Date.class, new RepresentDate());
56 this.multiRepresenters.put(Enum.class, new RepresentEnum());
57 this.multiRepresenters.put(Calendar.class, new RepresentDate());
58 classTags = new HashMap<Class<? extends Object>, Tag>();
59 }
60
61 protected Tag getTag(Class<?> clazz, Tag defaultTag) {
62 if (classTags.containsKey(clazz)) {
63 return classTags.get(clazz);
64 } else {
65 return defaultTag;
66 }
67 }
68
69
70
71
72
73
74
75
76
77
78
79
80 public Tag addClassTag(Class<? extends Object> clazz, String tag) {
81 return addClassTag(clazz, new Tag(tag));
82 }
83
84
85
86
87
88
89
90
91
92
93
94 public Tag addClassTag(Class<? extends Object> clazz, Tag tag) {
95 if (tag == null) {
96 throw new NullPointerException("Tag must be provided.");
97 }
98 return classTags.put(clazz, tag);
99 }
100
101 protected class RepresentNull implements Represent {
102 public Node representData(Object data) {
103 return representScalar(Tag.NULL, "null");
104 }
105 }
106
107 public static Pattern BINARY_PATTERN = Pattern.compile("[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]");
108
109 protected class RepresentString implements Represent {
110 public Node representData(Object data) {
111 Tag tag = Tag.STR;
112 Character style = null;
113 String value = data.toString();
114 if (BINARY_PATTERN.matcher(value).find()) {
115 tag = Tag.BINARY;
116 char[] binary;
117 binary = Base64Coder.encode(value.getBytes());
118 value = String.valueOf(binary);
119 style = '|';
120 }
121 return representScalar(tag, value, style);
122 }
123 }
124
125 protected class RepresentBoolean implements Represent {
126 public Node representData(Object data) {
127 String value;
128 if (Boolean.TRUE.equals(data)) {
129 value = "true";
130 } else {
131 value = "false";
132 }
133 return representScalar(Tag.BOOL, value);
134 }
135 }
136
137 protected class RepresentNumber implements Represent {
138 public Node representData(Object data) {
139 Tag tag;
140 String value;
141 if (data instanceof Byte || data instanceof Short || data instanceof Integer
142 || data instanceof Long || data instanceof BigInteger) {
143 tag = Tag.INT;
144 value = data.toString();
145 } else {
146 Number number = (Number) data;
147 tag = Tag.FLOAT;
148 if (number.equals(Double.NaN)) {
149 value = ".NaN";
150 } else if (number.equals(Double.POSITIVE_INFINITY)) {
151 value = ".inf";
152 } else if (number.equals(Double.NEGATIVE_INFINITY)) {
153 value = "-.inf";
154 } else {
155 value = number.toString();
156 }
157 }
158 return representScalar(getTag(data.getClass(), tag), value);
159 }
160 }
161
162 protected class RepresentList implements Represent {
163 @SuppressWarnings("unchecked")
164 public Node representData(Object data) {
165 return representSequence(getTag(data.getClass(), Tag.SEQ), (List<Object>) data, null);
166 }
167 }
168
169 protected class RepresentIterator implements Represent {
170 @SuppressWarnings("unchecked")
171 public Node representData(Object data) {
172 Iterator<Object> iter = (Iterator<Object>) data;
173 return representSequence(getTag(data.getClass(), Tag.SEQ), new IteratorWrapper(iter),
174 null);
175 }
176 }
177
178 private class IteratorWrapper implements Iterable<Object> {
179 private Iterator<Object> iter;
180
181 public IteratorWrapper(Iterator<Object> iter) {
182 this.iter = iter;
183 }
184
185 public Iterator<Object> iterator() {
186 return iter;
187 }
188 }
189
190 protected class RepresentArray implements Represent {
191 public Node representData(Object data) {
192 Object[] array = (Object[]) data;
193 List<Object> list = Arrays.asList(array);
194 return representSequence(Tag.SEQ, list, null);
195 }
196 }
197
198 protected class RepresentMap implements Represent {
199 @SuppressWarnings("unchecked")
200 public Node representData(Object data) {
201 return representMapping(getTag(data.getClass(), Tag.MAP), (Map<Object, Object>) data,
202 null);
203 }
204 }
205
206 protected class RepresentSet implements Represent {
207 @SuppressWarnings("unchecked")
208 public Node representData(Object data) {
209 Map<Object, Object> value = new LinkedHashMap<Object, Object>();
210 Set<Object> set = (Set<Object>) data;
211 for (Object key : set) {
212 value.put(key, null);
213 }
214 return representMapping(getTag(data.getClass(), Tag.SET), value, null);
215 }
216 }
217
218 protected class RepresentDate implements Represent {
219 public Node representData(Object data) {
220
221 Calendar calendar;
222 if (data instanceof Calendar) {
223 calendar = (Calendar) data;
224 } else {
225 calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
226 calendar.setTime((Date) data);
227 }
228 int years = calendar.get(Calendar.YEAR);
229 int months = calendar.get(Calendar.MONTH) + 1;
230 int days = calendar.get(Calendar.DAY_OF_MONTH);
231 int hour24 = calendar.get(Calendar.HOUR_OF_DAY);
232 int minutes = calendar.get(Calendar.MINUTE);
233 int seconds = calendar.get(Calendar.SECOND);
234 int millis = calendar.get(Calendar.MILLISECOND);
235 StringBuilder buffer = new StringBuilder(String.valueOf(years));
236 while (buffer.length() < 4) {
237
238 buffer.insert(0, "0");
239 }
240 buffer.append("-");
241 if (months < 10) {
242 buffer.append("0");
243 }
244 buffer.append(String.valueOf(months));
245 buffer.append("-");
246 if (days < 10) {
247 buffer.append("0");
248 }
249 buffer.append(String.valueOf(days));
250 buffer.append("T");
251 if (hour24 < 10) {
252 buffer.append("0");
253 }
254 buffer.append(String.valueOf(hour24));
255 buffer.append(":");
256 if (minutes < 10) {
257 buffer.append("0");
258 }
259 buffer.append(String.valueOf(minutes));
260 buffer.append(":");
261 if (seconds < 10) {
262 buffer.append("0");
263 }
264 buffer.append(String.valueOf(seconds));
265 if (millis > 0) {
266 if (millis < 10) {
267 buffer.append(".00");
268 } else if (millis < 100) {
269 buffer.append(".0");
270 } else {
271 buffer.append(".");
272 }
273 buffer.append(String.valueOf(millis));
274 }
275 if (TimeZone.getTimeZone("UTC").equals(calendar.getTimeZone())) {
276 buffer.append("Z");
277 } else {
278
279 int gmtOffset = calendar.getTimeZone().getOffset(calendar.get(Calendar.ERA),
280 calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
281 calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.DAY_OF_WEEK),
282 calendar.get(Calendar.MILLISECOND));
283 int minutesOffset = gmtOffset / (60 * 1000);
284 int hoursOffset = minutesOffset / 60;
285 int partOfHour = minutesOffset % 60;
286 buffer.append((hoursOffset > 0 ? "+" : "") + hoursOffset + ":"
287 + (partOfHour < 10 ? "0" + partOfHour : partOfHour));
288 }
289 return representScalar(getTag(data.getClass(), Tag.TIMESTAMP), buffer.toString(), null);
290 }
291 }
292
293 protected class RepresentEnum implements Represent {
294 public Node representData(Object data) {
295 Tag tag = new Tag(data.getClass());
296 return representScalar(getTag(data.getClass(), tag), ((Enum<?>) data).name());
297 }
298 }
299
300 protected class RepresentByteArray implements Represent {
301 public Node representData(Object data) {
302 char[] binary = Base64Coder.encode((byte[]) data);
303 return representScalar(Tag.BINARY, String.valueOf(binary), '|');
304 }
305 }
306 }