blob: 9ef824b29b3d5049438dcc987994e59f7e2cc205 [file] [log] [blame]
José Fonseca17a45412012-11-28 09:44:01 +00001/**************************************************************************
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
José Fonseca6083cfc2012-11-28 09:58:09 +000034#include <sstream>
35
36#include "image.hpp"
José Fonseca17a45412012-11-28 09:44:01 +000037#include "json.hpp"
38
39
40void
41JSONWriter::newline(void) {
42 os << "\n";
43 for (int i = 0; i < level; ++i)
44 os << " ";
45}
46
47void
48JSONWriter::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
68static void
69escapeAsciiString(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
94static void
95escapeUnicodeString(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
140static void
141encodeBase64String(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
198JSONWriter::JSONWriter(std::ostream &_os) :
199 os(_os),
200 level(0),
201 value(false),
202 space(0)
203{
204 beginObject();
205}
206
207JSONWriter::~JSONWriter() {
208 endObject();
209 newline();
210}
211
212void
213JSONWriter::beginObject() {
214 separator();
215 os << "{";
216 ++level;
217 value = false;
218}
219
220void
221JSONWriter::endObject() {
222 --level;
223 if (value)
224 newline();
225 os << "}";
226 value = true;
227 space = '\n';
228}
229
230void
231JSONWriter::beginMember(const char * name) {
232 space = 0;
233 separator();
234 newline();
235 escapeAsciiString(os, name);
236 os << ": ";
237 value = false;
238}
239
240void
241JSONWriter::endMember(void) {
242 assert(value);
243 value = true;
244 space = 0;
245}
246
247void
248JSONWriter::beginArray() {
249 separator();
250 os << "[";
251 ++level;
252 value = false;
253 space = 0;
254}
255
256void
257JSONWriter::endArray(void) {
258 --level;
259 if (space == '\n') {
260 newline();
261 }
262 os << "]";
263 value = true;
264 space = '\n';
265}
266
267void
268JSONWriter::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
280void
281JSONWriter::writeBase64(const void *bytes, size_t size) {
282 separator();
283 encodeBase64String(os, (const unsigned char *)bytes, size);
284 value = true;
285 space = ' ';
286}
287
288void
289JSONWriter::writeNull(void) {
290 separator();
291 os << "null";
292 value = true;
293 space = ' ';
294}
295
296void
297JSONWriter::writeBool(bool b) {
298 separator();
299 os << (b ? "true" : "false");
300 value = true;
301 space = ' ';
302}
José Fonseca6083cfc2012-11-28 09:58:09 +0000303
304void
José Fonseca42551442014-12-29 18:10:08 +0000305JSONWriter::writeImage(image::Image *image,
306 const ImageDesc & desc)
José Fonseca6083cfc2012-11-28 09:58:09 +0000307{
José Fonseca1085a4b2014-08-26 22:32:18 +0100308 assert(image);
José Fonseca65ba4972012-11-28 12:56:01 +0000309 if (!image) {
310 writeNull();
311 return;
312 }
313
José Fonseca6083cfc2012-11-28 09:58:09 +0000314 beginObject();
315
316 // Tell the GUI this is no ordinary object, but an image
317 writeStringMember("__class__", "image");
318
319 writeIntMember("__width__", image->width);
José Fonseca42551442014-12-29 18:10:08 +0000320 writeIntMember("__height__", image->height / desc.depth);
321 writeIntMember("__depth__", desc.depth);
José Fonseca6083cfc2012-11-28 09:58:09 +0000322
José Fonseca42551442014-12-29 18:10:08 +0000323 writeStringMember("__format__", desc.format.c_str());
José Fonseca6083cfc2012-11-28 09:58:09 +0000324
325 beginMember("__data__");
326 std::stringstream ss;
José Fonsecad67cc372013-09-12 17:27:04 +0100327
328 if (image->channelType == image::TYPE_UNORM8) {
329 image->writePNG(ss);
330 } else {
331 image->writePNM(ss);
332 }
333
José Fonseca6083cfc2012-11-28 09:58:09 +0000334 const std::string & s = ss.str();
335 writeBase64(s.data(), s.size());
336 endMember(); // __data__
337
338 endObject();
339}