]> git.saurik.com Git - apple/objc4.git/blob - objcdt/json.mm
objc4-787.1.tar.gz
[apple/objc4.git] / objcdt / json.mm
1 /*
2 * Copyright (c) 2019 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <assert.h>
25 #include "json.h"
26
27 namespace json {
28
29 static bool
30 context_is_value(context c)
31 {
32 return c == root || c == array_value || c == object_value;
33 }
34
35 writer::writer(FILE *f)
36 : _file(f)
37 , _context(root)
38 , _depth(0)
39 , _needs_comma(false)
40 {
41 }
42
43 writer::~writer()
44 {
45 fputc('\n', _file);
46 fflush(_file);
47 }
48
49 void
50 writer::begin_value(int sep)
51 {
52 if (_needs_comma) {
53 _needs_comma = false;
54 if (sep) {
55 fprintf(_file, ", %c\n", sep);
56 return;
57 }
58 fputs(",\n", _file);
59 }
60 if (_context == array_value || _context == object_key) {
61 fprintf(_file, "%*s", _depth * 2, "");
62 }
63 if (sep) {
64 fprintf(_file, "%c\n", sep);
65 }
66 }
67
68 void
69 writer::advance(context c)
70 {
71 switch (c) {
72 case root:
73 _context = done;
74 _needs_comma = false;
75 break;
76 case array_value:
77 _context = array_value;
78 _needs_comma = true;
79 break;
80 case object_value:
81 _context = object_key;
82 _needs_comma = true;
83 break;
84 case object_key:
85 _context = object_value;
86 _needs_comma = false;
87 break;
88 case done:
89 assert(false);
90 break;
91 }
92 }
93
94 void
95 writer::key(const char *key)
96 {
97 assert(_context == object_key);
98
99 begin_value();
100 fprintf(_file, "\"%s\": ", key);
101 advance(_context);
102 }
103
104 void
105 writer::object(std::function<void()> f)
106 {
107 context old = _context;
108 assert(context_is_value(old));
109
110 begin_value('{');
111
112 _depth++;
113 _context = object_key;
114 _needs_comma = false;
115 f();
116
117 _depth--;
118 fprintf(_file, "\n%*s}", _depth * 2, "");
119 advance(old);
120 }
121
122 void
123 writer::object(const char *k, std::function<void()> f)
124 {
125 key(k);
126 object(f);
127 }
128
129 void
130 writer::array(std::function<void()> f)
131 {
132 context old = _context;
133 assert(context_is_value(old));
134
135 begin_value('[');
136
137 _depth++;
138 _context = array_value;
139 _needs_comma = false;
140 f();
141
142 _depth--;
143 fprintf(_file, "\n%*s]", _depth * 2, "");
144 advance(old);
145 }
146
147 void
148 writer::array(const char *k, std::function<void()> f)
149 {
150 key(k);
151 array(f);
152 }
153
154 void
155 writer::boolean(bool value)
156 {
157 assert(context_is_value(_context));
158 begin_value();
159 fputs(value ? "true" : "false", _file);
160 advance(_context);
161 }
162
163 void
164 writer::boolean(const char *k, bool value)
165 {
166 key(k);
167 boolean(value);
168 }
169
170 void
171 writer::number(uint64_t value)
172 {
173 assert(context_is_value(_context));
174 begin_value();
175 fprintf(_file, "%lld", value);
176 advance(_context);
177 }
178
179 void
180 writer::number(const char *k, uint64_t value)
181 {
182 key(k);
183 number(value);
184 }
185
186 void
187 writer::string(const char *s)
188 {
189 assert(context_is_value(_context));
190 begin_value();
191 fprintf(_file, "\"%s\"", s);
192 advance(_context);
193 }
194
195 void
196 writer::string(const char *k, const char *s)
197 {
198 key(k);
199 string(s);
200 }
201
202 void
203 writer::stringf(const char *fmt, ...)
204 {
205 va_list ap;
206
207 assert(context_is_value(_context));
208 begin_value();
209 fputc('"', _file);
210 va_start(ap, fmt);
211 vfprintf(_file, fmt, ap);
212 va_end(ap);
213 fputc('"', _file);
214 advance(_context);
215 }
216
217 void
218 writer::stringf(const char *k, const char *fmt, ...)
219 {
220 va_list ap;
221
222 key(k);
223
224 assert(context_is_value(_context));
225 begin_value();
226 fputc('"', _file);
227 va_start(ap, fmt);
228 vfprintf(_file, fmt, ap);
229 va_end(ap);
230 fputc('"', _file);
231 advance(_context);
232 }
233
234 } // json