]> git.cworth.org Git - apitrace/blob - retrace/json.cpp
glretrace: reapply fix for #178 to original GLX code
[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 <sstream>
35
36 #include "image.hpp"
37 #include "json.hpp"
38
39
40 void
41 JSONWriter::newline(void) {
42     os << "\n";
43     for (int i = 0; i < level; ++i)
44         os << "  ";
45 }
46
47 void
48 JSONWriter::separator(void) {
49     if (value) {
50         os << ",";
51         switch (space) {
52         case '\0':
53             break;
54         case '\n':
55             newline();
56             break;
57         default:
58             os << space;
59             break;
60         }
61     } else {
62         if (space == '\n') {
63             newline();
64         }
65     }
66 }
67
68 static void
69 escapeAsciiString(std::ostream &os, const char *str) {
70     os << "\"";
71
72     const unsigned char *src = (const unsigned char *)str;
73     unsigned char c;
74     while ((c = *src++)) {
75         if ((c == '\"') ||
76             (c == '\\')) {
77             // escape character
78             os << '\\' << (unsigned char)c;
79         } else if ((c >= 0x20 && c <= 0x7e) ||
80                     c == '\t' ||
81                     c == '\r' ||
82                     c == '\n') {
83             // pass-through character
84             os << (unsigned char)c;
85         } else {
86             assert(0);
87             os << "?";
88         }
89     }
90
91     os << "\"";
92 }
93
94 static void
95 escapeUnicodeString(std::ostream &os, const char *str) {
96     os << "\"";
97
98     const char *locale = setlocale(LC_CTYPE, "");
99     const char *src = str;
100     mbstate_t state;
101
102     memset(&state, 0, sizeof state);
103
104     do {
105         // Convert characters one at a time in order to recover from
106         // conversion errors
107         wchar_t c;
108         size_t written = mbsrtowcs(&c, &src, 1, &state);
109         if (written == 0) {
110             // completed
111             break;
112         } if (written == (size_t)-1) {
113             // conversion error -- skip
114             os << "?";
115             do {
116                 ++src;
117             } while (*src & 0x80);
118         } else if ((c == '\"') ||
119                    (c == '\\')) {
120             // escape character
121             os << '\\' << (unsigned char)c;
122         } else if ((c >= 0x20 && c <= 0x7e) ||
123                     c == '\t' ||
124                     c == '\r' ||
125                     c == '\n') {
126             // pass-through character
127             os << (unsigned char)c;
128         } else {
129             // unicode
130             os << "\\u" << std::setfill('0') << std::hex << std::setw(4) << (unsigned)c;
131             os << std::dec;
132         }
133     } while (src);
134
135     setlocale(LC_CTYPE, locale);
136
137     os << "\"";
138 }
139
140 static void
141 encodeBase64String(std::ostream &os, const unsigned char *bytes, size_t size) {
142     const char *table64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
143     unsigned char c0, c1, c2, c3;
144     char buf[4];
145     unsigned written;
146
147     os << "\"";
148
149     written = 0;
150     while (size >= 3) {
151         c0 = bytes[0] >> 2;
152         c1 = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xf0) >> 4);
153         c2 = ((bytes[1] & 0x0f) << 2) | ((bytes[2] & 0xc0) >> 6);
154         c3 = bytes[2] & 0x3f;
155
156         buf[0] = table64[c0];
157         buf[1] = table64[c1];
158         buf[2] = table64[c2];
159         buf[3] = table64[c3];
160
161         os.write(buf, 4);
162
163         bytes += 3;
164         size -= 3;
165         ++written;
166
167         if (written >= 76/4 && size) {
168             os << "\n";
169             written = 0;
170         }
171     }
172
173     if (size > 0) {
174         c0 = bytes[0] >> 2;
175         c1 = ((bytes[0] & 0x03) << 4);
176         buf[2] = '=';
177         buf[3] = '=';
178
179         if (size > 1) {
180             c1 |= ((bytes[1] & 0xf0) >> 4);
181             c2 = ((bytes[1] & 0x0f) << 2);
182             if (size > 2) {
183                 c2 |= ((bytes[2] & 0xc0) >> 6);
184                 c3 = bytes[2] & 0x3f;
185                 buf[3] = table64[c3];
186             }
187             buf[2] = table64[c2];
188         }
189         buf[1] = table64[c1];
190         buf[0] = table64[c0];
191
192         os.write(buf, 4);
193     }
194
195     os << "\"";
196 }
197
198 JSONWriter::JSONWriter(std::ostream &_os) :
199     os(_os),
200     level(0),
201     value(false),
202     space(0)
203 {
204     beginObject();
205 }
206
207 JSONWriter::~JSONWriter() {
208     endObject();
209     newline();
210 }
211
212 void
213 JSONWriter::beginObject() {
214     separator();
215     os << "{";
216     ++level;
217     value = false;
218 }
219
220 void
221 JSONWriter::endObject() {
222     --level;
223     if (value)
224         newline();
225     os << "}";
226     value = true;
227     space = '\n';
228 }
229
230 void
231 JSONWriter::beginMember(const char * name) {
232     space = 0;
233     separator();
234     newline();
235     escapeAsciiString(os, name);
236     os << ": ";
237     value = false;
238 }
239
240 void
241 JSONWriter::endMember(void) {
242     assert(value);
243     value = true;
244     space = 0;
245 }
246
247 void
248 JSONWriter::beginArray() {
249     separator();
250     os << "[";
251     ++level;
252     value = false;
253     space = 0;
254 }
255
256 void
257 JSONWriter::endArray(void) {
258     --level;
259     if (space == '\n') {
260         newline();
261     }
262     os << "]";
263     value = true;
264     space = '\n';
265 }
266
267 void
268 JSONWriter::writeString(const char *s) {
269     if (!s) {
270         writeNull();
271         return;
272     }
273
274     separator();
275     escapeUnicodeString(os, s);
276     value = true;
277     space = ' ';
278 }
279
280 void
281 JSONWriter::writeBase64(const void *bytes, size_t size) {
282     separator();
283     encodeBase64String(os, (const unsigned char *)bytes, size);
284     value = true;
285     space = ' ';
286 }
287
288 void
289 JSONWriter::writeNull(void) {
290     separator();
291     os << "null";
292     value = true;
293     space = ' ';
294 }
295
296 void
297 JSONWriter::writeBool(bool b) {
298     separator();
299     os << (b ? "true" : "false");
300     value = true;
301     space = ' ';
302 }
303
304 void
305 JSONWriter::writeImage(image::Image *image, const char *format, unsigned depth)
306 {
307     if (!image) {
308         writeNull();
309         return;
310     }
311
312     beginObject();
313
314     // Tell the GUI this is no ordinary object, but an image
315     writeStringMember("__class__", "image");
316
317     writeIntMember("__width__", image->width);
318     writeIntMember("__height__", image->height / depth);
319     writeIntMember("__depth__", depth);
320
321     writeStringMember("__format__", format);
322
323     beginMember("__data__");
324     std::stringstream ss;
325
326     if (image->channelType == image::TYPE_UNORM8) {
327         image->writePNG(ss);
328     } else {
329         image->writePNM(ss);
330     }
331
332     const std::string & s = ss.str();
333     writeBase64(s.data(), s.size());
334     endMember(); // __data__
335
336     endObject();
337 }