comparison artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/JSON.java @ 472:783cc1b6b615

Moved directories to org.dive4elements
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 25 Apr 2013 10:53:15 +0200
parents artifacts-common/src/main/java/de/intevation/artifacts/common/utils/JSON.java@c40729bfe06d
children 415df0fc4fa1
comparison
equal deleted inserted replaced
471:1a87cb24a446 472:783cc1b6b615
1 package de.intevation.artifacts.common.utils;
2
3 import java.util.Map;
4 import java.util.LinkedHashMap;
5 import java.util.List;
6 import java.util.ArrayList;
7 import java.util.Iterator;
8
9 import java.io.IOException;
10 import java.io.PushbackInputStream;
11 import java.io.InputStream;
12 import java.io.PrintWriter;
13 import java.io.ByteArrayInputStream;
14 import java.io.StringWriter;
15
16 import java.nio.charset.Charset;
17 import java.nio.charset.UnsupportedCharsetException;
18
19 public final class JSON
20 {
21 private JSON() {
22 }
23
24 private static final boolean isDigit(int c) {
25 return c >= '0' && c <= '9';
26 }
27
28 public static final boolean isWhitespace(int c) {
29 return c == ' ' || c == '\n' || c == '\r'
30 || c == '\t' || c == '\f';
31 }
32
33 private static final void match(int c, int x) throws IOException {
34 if (c != x) {
35 throw new IOException(
36 "Expecting '" + (char)c + "' found '" + (char)x + "'");
37 }
38 }
39
40 private static final int eof(InputStream in)
41 throws IOException
42 {
43 int c = in.read();
44 if (c == -1) {
45 throw new IOException("EOF unexpected.");
46 }
47 return c;
48 }
49
50 private static final int whitespace(InputStream in)
51 throws IOException
52 {
53 int c;
54 while (isWhitespace(c = eof(in)));
55 return c;
56 }
57
58 private static final int parseHex(String hex) throws IOException {
59 try {
60 return Integer.parseInt(hex, 16);
61 }
62 catch (NumberFormatException nfe) {
63 throw new IOException("'" + hex + "' is not a hex string.");
64 }
65 }
66
67 public static final String jsonString(String string) {
68 StringBuilder sb = new StringBuilder(string.length()+2);
69
70 sb.append('"');
71
72 for (int i = 0, N = string.length(); i < N; ++i) {
73 char c = string.charAt(i);
74 switch (c) {
75 case '"': sb.append("\\\""); break;
76 case '\t': sb.append("\\t"); break;
77 case '\r': sb.append("\\r"); break;
78 case '\n': sb.append("\\n"); break;
79 case '\b': sb.append("\\b"); break;
80 case '\f': sb.append("\\f"); break;
81 default:
82 if (c >= 128) {
83 sb.append("\\u");
84 String hex = Integer.toHexString((int)c);
85 for (int j = 4-hex.length(); j > 0; --j) {
86 sb.append('0');
87 }
88 sb.append(hex);
89 }
90 else {
91 sb.append(c);
92 }
93 }
94 }
95
96 sb.append('"');
97
98 return sb.toString();
99 }
100
101 public static String toJSONString(Map<String, Object> map) {
102 StringWriter sw = new StringWriter();
103 PrintWriter pw = new PrintWriter(sw);
104 write(pw, map);
105 pw.flush();
106 return sw.toString();
107 }
108
109
110 public static void write(PrintWriter out, Map<String, Object> map) {
111 writeObject(out, map);
112 }
113
114 private static void writeValue(PrintWriter out, Object value) {
115 if (value instanceof Map) {
116 writeObject(out, (Map)value);
117 }
118 else if (value instanceof List) {
119 writeList(out, (List)value);
120 }
121 else if (value instanceof Number) {
122 out.print(value);
123 }
124 else if (value instanceof Boolean) {
125 out.print(((Boolean)value) ? "true" : "false");
126 }
127 else if (value == null) {
128 out.print("null");
129 }
130 else {
131 out.print(jsonString(value.toString()));
132 }
133 }
134
135 private static void writeObject(PrintWriter out, Map map) {
136
137 out.print('{');
138 Iterator iter = map.entrySet().iterator();
139 while (iter.hasNext()) {
140 Map.Entry entry = (Map.Entry)iter.next();
141 out.print(jsonString(entry.getKey().toString()));
142 out.print(':');
143 writeValue(out, entry.getValue());
144 if (iter.hasNext()) {
145 out.print(',');
146 }
147 }
148 out.print('}');
149 }
150
151 private static void writeList(PrintWriter out, List list) {
152 out.print('[');
153 Iterator iter = list.iterator();
154 while (iter.hasNext()) {
155 writeValue(out, iter.next());
156 if (iter.hasNext()) {
157 out.print(',');
158 }
159 }
160 out.print(']');
161 }
162
163 public static Map<String, Object> parse(String in)
164 throws IOException
165 {
166 return parse(asInputStream(in));
167 }
168
169 private static InputStream asInputStream(String in) {
170 byte [] bytes;
171 try {
172 bytes = in.getBytes(Charset.forName("US-ASCII"));
173 }
174 catch (UnsupportedCharsetException uce) {
175 // Should not happen.
176 bytes = in.getBytes();
177 }
178 return new ByteArrayInputStream(bytes);
179 }
180
181 public static Map<String, Object> parse(InputStream in)
182 throws IOException
183 {
184 return parseObject(new PushbackInputStream(in, 1));
185 }
186
187 public static Map<String, Object> parse(PushbackInputStream in)
188 throws IOException
189 {
190 return parseObject(in);
191 }
192
193 private static final String parseString(
194 PushbackInputStream in
195 )
196 throws IOException
197 {
198 StringBuilder sb = new StringBuilder();
199
200 int mode = 0;
201
202 char [] hex = new char[4];
203
204 match('"', eof(in));
205
206 OUT: for (int c = eof(in);; c = eof(in)) {
207
208 switch (mode) {
209 case 0:
210 if (c == '"') {
211 break OUT;
212 }
213 if (c == '\\') {
214 mode = 1;
215 }
216 else {
217 sb.append((char)c);
218 }
219 break;
220 case 1:
221 switch (c) {
222 case 'u':
223 mode = 2;
224 continue;
225 case 'b':
226 sb.append('\b');
227 break;
228 case 'f':
229 sb.append('\f');
230 break;
231 case 'n':
232 sb.append('\n');
233 break;
234 case 'r':
235 sb.append('\r');
236 break;
237 case 't':
238 sb.append('\t');
239 break;
240 default:
241 sb.append((char)c);
242 }
243 mode = 0;
244 break;
245 case 2:
246 hex[0] = (char)c;
247 mode = 3;
248 break;
249 case 3:
250 hex[1] = (char)c;
251 mode = 4;
252 break;
253 case 4:
254 hex[2] = (char)c;
255 mode = 5;
256 break;
257 case 5:
258 hex[3] = (char)c;
259 sb.append((char)parseHex(new String(hex)));
260 mode = 0;
261 break;
262 }
263 }
264 return sb.toString();
265 }
266
267 private static final Boolean parseTrue(InputStream in)
268 throws IOException
269 {
270 match('t', eof(in));
271 match('r', eof(in));
272 match('u', eof(in));
273 match('e', eof(in));
274 return Boolean.TRUE;
275 }
276
277 private static final Boolean parseFalse(InputStream in)
278 throws IOException
279 {
280 match('f', eof(in));
281 match('a', eof(in));
282 match('l', eof(in));
283 match('s', eof(in));
284 match('e', eof(in));
285 return Boolean.FALSE;
286 }
287
288 private static final Object parseNull(InputStream in)
289 throws IOException
290 {
291 match('n', eof(in));
292 match('u', eof(in));
293 match('l', eof(in));
294 match('l', eof(in));
295 return null;
296 }
297
298 private static final Number parseNumber(PushbackInputStream in)
299 throws IOException
300 {
301 StringBuilder sb = new StringBuilder();
302
303 boolean isInteger = true;
304
305 int c;
306 OUT: for (;;) {
307 switch (c = eof(in)) {
308 case '0': case '1': case '2': case '3': case '4':
309 case '5': case '6': case '7': case '8': case '9':
310 case '-': case '+':
311 sb.append((char)c);
312 break;
313 case '.': case 'e': case 'E':
314 isInteger = false;
315 sb.append((char)c);
316 break;
317 default:
318 in.unread(c);
319 break OUT;
320 }
321 }
322
323 try {
324 if (isInteger) {
325 return sb.length() > 9
326 ? (Number)Long .valueOf(sb.toString())
327 : (Number)Integer.valueOf(sb.toString());
328 }
329 return (Number)Double.valueOf(sb.toString());
330 }
331 catch (NumberFormatException nfe) {
332 throw new IOException("Not a number '" + sb + "'");
333 }
334 }
335
336 private static List<Object> parseList(PushbackInputStream in)
337 throws IOException
338 {
339 List<Object> list = new ArrayList<Object>();
340 match('[', whitespace(in));
341 int c = whitespace(in);
342 if (c == ']') {
343 return list;
344 }
345
346 for (;; c = whitespace(in)) {
347 Object value;
348 in.unread(c);
349 switch (c) {
350 case '{':
351 value = parseObject(in);
352 break;
353 case '[':
354 value = parseList(in);
355 break;
356 case '"':
357 value = parseString(in);
358 break;
359 case 't':
360 value = parseTrue(in);
361 break;
362 case 'f':
363 value = parseFalse(in);
364 break;
365 case 'n':
366 value = parseNull(in);
367 break;
368 default:
369 value = parseNumber(in);
370 }
371 list.add(value);
372
373 if ((c = whitespace(in)) == ']') break;
374 match(',', c);
375 }
376 return list;
377 }
378
379 private static void parsePair(
380 PushbackInputStream in,
381 Map<String, Object> pairs
382 )
383 throws IOException
384 {
385 in.unread(whitespace(in));
386 String string = parseString(in);
387 match(':', whitespace(in));
388
389 Object value;
390
391 int c = whitespace(in);
392 in.unread(c);
393 switch (c) {
394 case '{':
395 value = parseObject(in);
396 break;
397 case '[':
398 value = parseList(in);
399 break;
400 case '"':
401 value = parseString(in);
402 break;
403 case 't':
404 value = parseTrue(in);
405 break;
406 case 'f':
407 value = parseFalse(in);
408 break;
409 case 'n':
410 value = parseNull(in);
411 break;
412 default:
413 value = parseNumber(in);
414 }
415 pairs.put(string, value);
416 }
417
418 private static Map<String, Object> parseObject(PushbackInputStream in)
419 throws IOException
420 {
421 Map<String, Object> pairs = new LinkedHashMap<String, Object>();
422
423 int c = whitespace(in);
424 match('{', c);
425
426 if ((c = whitespace(in)) == '}') {
427 return pairs;
428 }
429
430 in.unread(c);
431
432 for (;;) {
433 parsePair(in, pairs);
434
435 if ((c = whitespace(in)) == '}') {
436 break;
437 }
438
439 if (c == '}') break;
440 match(',', c);
441 }
442
443 return pairs;
444 }
445 }

http://dive4elements.wald.intevation.org