]> git.cworth.org Git - apitrace/blob - retrace/json.cpp
e500aa67b9a2fc086c264a332ea20faec17c8904
[apitrace] / retrace / json.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 /*
27  * JSON writing functions.
28  */
29
30
31 #include <assert.h>
32 #include <string.h>
33
34 #include "json.hpp"
35
36
37 void
38 JSONWriter::newline(void) {
39     os << "\n";
40     for (int i = 0; i < level; ++i)
41         os << "  ";
42 }
43
44 void
45 JSONWriter::separator(void) {
46     if (value) {
47         os << ",";
48         switch (space) {
49         case '\0':
50             break;
51         case '\n':
52             newline();
53             break;
54         default:
55             os << space;
56             break;
57         }
58     } else {
59         if (space == '\n') {
60             newline();
61         }
62     }
63 }
64
65 static void
66 escapeAsciiString(std::ostream &os, const char *str) {
67     os << "\"";
68
69     const unsigned char *src = (const unsigned char *)str;
70     unsigned char c;
71     while ((c = *src++)) {
72         if ((c == '\"') ||
73             (c == '\\')) {
74             // escape character
75             os << '\\' << (unsigned char)c;
76         } else if ((c >= 0x20 && c <= 0x7e) ||
77                     c == '\t' ||
78                     c == '\r' ||
79                     c == '\n') {
80             // pass-through character
81             os << (unsigned char)c;
82         } else {
83             assert(0);
84             os << "?";
85         }
86     }
87
88     os << "\"";
89 }
90
91 static void
92 escapeUnicodeString(std::ostream &os, const char *str) {
93     os << "\"";
94
95     const char *locale = setlocale(LC_CTYPE, "");
96     const char *src = str;
97     mbstate_t state;
98
99     memset(&state, 0, sizeof state);
100
101     do {
102         // Convert characters one at a time in order to recover from
103         // conversion errors
104         wchar_t c;
105         size_t written = mbsrtowcs(&c, &src, 1, &state);
106         if (written == 0) {
107             // completed
108             break;
109         } if (written == (size_t)-1) {
110             // conversion error -- skip
111             os << "?";
112             do {
113                 ++src;
114             } while (*src & 0x80);
115         } else if ((c == '\"') ||
116                    (c == '\\')) {
117             // escape character
118             os << '\\' << (unsigned char)c;
119         } else if ((c >= 0x20 && c <= 0x7e) ||
120                     c == '\t' ||
121                     c == '\r' ||
122                     c == '\n') {
123             // pass-through character
124             os << (unsigned char)c;
125         } else {
126             // unicode
127             os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c;
128             os << std::dec;
129         }
130     } while (src);
131
132     setlocale(LC_CTYPE, locale);
133
134     os << "\"";
135 }
136
137 static void
138 encodeBase64String(std::ostream &os, const unsigned char *bytes, size_t size) {
139     const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
140     unsigned char c0, c1, c2, c3;
141     char buf[4];
142     unsigned written;
143
144     os << "\"";
145
146     written = 0;
147     while (size >= 3) {
148         c0 = bytes[0] >> 2;
149         c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4);
150         c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6);
151         c3 = bytes[2] & 0x3f;
152
153         buf[0] = table64[c0];
154         buf[1] = table64[c1];
155         buf[2] = table64[c2];
156         buf[3] = table64[c3];
157
158         os.write(buf, 4);
159
160         bytes += 3;
161         size -= 3;
162         ++written;
163
164         if (written >= 76/4 && size) {
165             os << "\n";
166             written = 0;
167         }
168     }
169
170     if (size > 0) {
171         c0 = bytes[0] >> 2;
172         c1 = ((bytes[0] & 0x03) << 4);
173         buf[2] = '=';
174         buf[3] = '=';
175
176         if (size > 1) {
177             c1 |= ((bytes[1] & 0xf0) >> 4);
178             c2 = ((bytes[1] & 0x0f) << 2);
179             if (size > 2) {
180                 c2 |= ((bytes[2] & 0xc0) >> 6);
181                 c3 = bytes[2] & 0x3f;
182                 buf[3] = table64[c3];
183             }
184             buf[2] = table64[c2];
185         }
186         buf[1] = table64[c1];
187         buf[0] = table64[c0];
188
189         os.write(buf, 4);
190     }
191
192     os << "\"";
193 }
194
195 JSONWriter::JSONWriter(std::ostream &_os) :
196     os(_os),
197     level(0),
198     value(false),
199     space(0)
200 {
201     beginObject();
202 }
203
204 JSONWriter::~JSONWriter() {
205     endObject();
206     newline();
207 }
208
209 void
210 JSONWriter::beginObject() {
211     separator();
212     os << "{";
213     ++level;
214     value = false;
215 }
216
217 void
218 JSONWriter::endObject() {
219     --level;
220     if (value)
221         newline();
222     os << "}";
223     value = true;
224     space = '\n';
225 }
226
227 void
228 JSONWriter::beginMember(const char * name) {
229     space = 0;
230     separator();
231     newline();
232     escapeAsciiString(os, name);
233     os << ": ";
234     value = false;
235 }
236
237 void
238 JSONWriter::endMember(void) {
239     assert(value);
240     value = true;
241     space = 0;
242 }
243
244 void
245 JSONWriter::beginArray() {
246     separator();
247     os << "[";
248     ++level;
249     value = false;
250     space = 0;
251 }
252
253 void
254 JSONWriter::endArray(void) {
255     --level;
256     if (space == '\n') {
257         newline();
258     }
259     os << "]";
260     value = true;
261     space = '\n';
262 }
263
264 void
265 JSONWriter::writeString(const char *s) {
266     if (!s) {
267         writeNull();
268         return;
269     }
270
271     separator();
272     escapeUnicodeString(os, s);
273     value = true;
274     space = ' ';
275 }
276
277 void
278 JSONWriter::writeBase64(const void *bytes, size_t size) {
279     separator();
280     encodeBase64String(os, (const unsigned char *)bytes, size);
281     value = true;
282     space = ' ';
283 }
284
285 void
286 JSONWriter::writeNull(void) {
287     separator();
288     os << "null";
289     value = true;
290     space = ' ';
291 }
292
293 void
294 JSONWriter::writeBool(bool b) {
295     separator();
296     os << (b ? "true" : "false");
297     value = true;
298     space = ' ';
299 }