blob: 2450ed0040692c852de8ad65608f730f26b16c83 [file] [log] [blame]
Stuart McCullochf3173222012-06-07 21:57:32 +00001package aQute.lib.json;
2
3import java.io.*;
4import java.lang.reflect.*;
5import java.util.*;
6
7public class StringHandler extends Handler {
8
9 @Override void encode(Encoder app, Object object, Map<Object, Type> visited)
10 throws IOException {
11 string(app, object.toString());
12 }
13
14 static void string(Appendable app, String s) throws IOException {
15
16 app.append('"');
17 for (int i = 0; i < s.length(); i++) {
18 char c = s.charAt(i);
19 switch (c) {
20 case '"':
21 app.append("\\\"");
22 break;
23
24 case '\\':
25 app.append("\\\\");
26 break;
27
28 case '\b':
29 app.append("\\b");
30 break;
31
32 case '\f':
33 app.append("\\f");
34 break;
35
36 case '\n':
37 app.append("\\n");
38 break;
39
40 case '\r':
41 app.append("\\r");
42 break;
43
44 case '\t':
45 app.append("\\t");
46 break;
47
48 default:
49 if (Character.isISOControl(c)) {
50 app.append("\\u");
51 app.append("0123456789ABCDEF".charAt(0xF & (c >> 12)));
52 app.append("0123456789ABCDEF".charAt(0xF & (c >> 8)));
53 app.append("0123456789ABCDEF".charAt(0xF & (c >> 4)));
54 app.append("0123456789ABCDEF".charAt(0xF & (c >> 0)));
55 } else
56 app.append(c);
57 }
58 }
59 app.append('"');
60 }
61
62 Object decode(String s) throws Exception {
63 return s;
64 }
65
66 Object decode(Number s) {
67 return s.toString();
68 }
69
70 Object decode(boolean s) {
71 return Boolean.toString(s);
72 }
73
74 Object decode() {
75 return null;
76 }
77
78 /**
79 * An object can be assigned to a string. This means that the stream is
80 * interpreted as the object but stored in its complete in the string.
81 */
82 Object decodeObject(Decoder r) throws Exception {
83 return collect(r, '}');
84 }
85
86 /**
87 * An array can be assigned to a string. This means that the stream is
88 * interpreted as the array but stored in its complete in the string.
89 */
90 Object decodeArray(Decoder r) throws Exception {
91 return collect(r, ']');
92 }
93
94 /**
95 * Gather the input until you find the the closing character making sure
96 * that new blocks are are take care of.
97 * <p>
98 * This method parses the input for a complete block so that it can be
99 * stored in a string. This allows envelopes.
100 *
101 * @param isr
102 * @param c
103 * @return
104 * @throws Exception
105 */
106 private Object collect(Decoder isr, char close) throws Exception {
107 boolean instring = false;
108 int level = 1;
109 StringBuilder sb = new StringBuilder();
110
111 int c = isr.current();
112 while (c > 0 && level > 0) {
113 sb.append((char) c);
114 if (instring)
115 switch (c) {
116 case '"':
117 instring = true;
118 break;
119
120 case '[':
121 case '{':
122 level++;
123 break;
124
125 case ']':
126 case '}':
127 level--;
128 break;
129 }
130 else
131 switch (c) {
132 case '"':
133 instring = false;
134 break;
135
136 case '\\':
137 sb.append((char) isr.read());
138 break;
139 }
140
141 c = isr.read();
142 }
143 return sb.toString();
144 }
145
146}