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