xref: /haiku/src/kits/shared/JsonMessageWriter.cpp (revision 1f6b57a5d2aade703945e8c51aeaf332f6c222de)
1 /*
2  * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "JsonMessageWriter.h"
7 
8 #include <stdio.h>
9 
10 
11 namespace BPrivate {
12 
13 /*! The class and sub-classes of it are used as a stack internal to the
14     BJsonMessageWriter class.  As the JSON is parsed, the stack of these
15     internal listeners follows the stack of the JSON parsing in terms of
16     containers; arrays and objects.
17 */
18 
19 class BStackedMessageEventListener : public BJsonEventListener {
20 public:
21 								BStackedMessageEventListener(
22 									BJsonMessageWriter* writer,
23 									BStackedMessageEventListener* parent,
24 									uint32 messageWhat);
25 								BStackedMessageEventListener(
26 									BJsonMessageWriter* writer,
27 									BStackedMessageEventListener* parent,
28 									BMessage* message);
29 								~BStackedMessageEventListener();
30 
31 				bool			Handle(const BJsonEvent& event);
32 				void			HandleError(status_t status, int32 line,
33 									const char* message);
34 				void			Complete();
35 
36 				void			AddMessage(BMessage* value);
37 
38 				status_t		ErrorStatus();
39 		virtual	const char*		NextItemName() = 0;
40 
41 				BStackedMessageEventListener*
42 								Parent();
43 
44 protected:
45 				void			AddBool(bool value);
46 				void			AddNull();
47 				void			AddDouble(double value);
48 				void			AddString(const char* value);
49 
50 		virtual bool			WillAdd();
51 		virtual void			DidAdd();
52 
53 				void			SetStackedListenerOnWriter(
54 									BStackedMessageEventListener*
55 									stackedListener);
56 
57 			BJsonMessageWriter*	fWriter;
58 			bool				fOwnsMessage;
59 			BStackedMessageEventListener
60 								*fParent;
61 			BMessage*			fMessage;
62 };
63 
64 
65 class BStackedArrayMessageEventListener : public BStackedMessageEventListener {
66 public:
67 								BStackedArrayMessageEventListener(
68 									BJsonMessageWriter* writer,
69 									BStackedMessageEventListener* parent);
70 								BStackedArrayMessageEventListener(
71 									BJsonMessageWriter* writer,
72 									BStackedMessageEventListener* parent,
73 									BMessage* message);
74 								~BStackedArrayMessageEventListener();
75 
76 				bool			Handle(const BJsonEvent& event);
77 
78 				const char*		NextItemName();
79 
80 protected:
81 				void			DidAdd();
82 
83 private:
84 				uint32			fCount;
85 				BString			fNextItemName;
86 
87 };
88 
89 
90 class BStackedObjectMessageEventListener : public BStackedMessageEventListener {
91 public:
92 								BStackedObjectMessageEventListener(
93 									BJsonMessageWriter* writer,
94 									BStackedMessageEventListener* parent);
95 								BStackedObjectMessageEventListener(
96 									BJsonMessageWriter* writer,
97 									BStackedMessageEventListener* parent,
98 									BMessage* message);
99 								~BStackedObjectMessageEventListener();
100 
101 				bool			Handle(const BJsonEvent& event);
102 
103 				const char*		NextItemName();
104 
105 protected:
106 				bool			WillAdd();
107 				void			DidAdd();
108 private:
109 				BString			fNextItemName;
110 };
111 
112 } // namespace BPrivate
113 
114 using BPrivate::BStackedMessageEventListener;
115 using BPrivate::BStackedArrayMessageEventListener;
116 using BPrivate::BStackedObjectMessageEventListener;
117 
118 
119 // #pragma mark - BStackedMessageEventListener
120 
121 
122 BStackedMessageEventListener::BStackedMessageEventListener(
123 	BJsonMessageWriter* writer,
124 	BStackedMessageEventListener* parent,
125 	uint32 messageWhat)
126 {
127 	fWriter = writer;
128 	fParent = parent;
129 	fOwnsMessage = true;
130 	fMessage = new BMessage(messageWhat);
131 }
132 
133 
134 BStackedMessageEventListener::BStackedMessageEventListener(
135 	BJsonMessageWriter* writer,
136 	BStackedMessageEventListener* parent,
137 	BMessage* message)
138 {
139 	fWriter = writer;
140 	fParent = parent;
141 	fOwnsMessage = false;
142 	fMessage = message;
143 }
144 
145 
146 BStackedMessageEventListener::~BStackedMessageEventListener()
147 {
148 	if (fOwnsMessage)
149 		delete fMessage;
150 }
151 
152 
153 bool
154 BStackedMessageEventListener::Handle(const BJsonEvent& event)
155 {
156 	if (fWriter->ErrorStatus() != B_OK)
157 		return false;
158 
159 	switch (event.EventType()) {
160 
161 		case B_JSON_NUMBER:
162 			AddDouble(event.ContentDouble());
163 			break;
164 
165 		case B_JSON_STRING:
166 			AddString(event.Content());
167 			break;
168 
169 		case B_JSON_TRUE:
170 			AddBool(true);
171 			break;
172 
173 		case B_JSON_FALSE:
174 			AddBool(false);
175 			break;
176 
177 		case B_JSON_NULL:
178 			AddNull();
179 			break;
180 
181 		case B_JSON_OBJECT_START:
182 			SetStackedListenerOnWriter(new BStackedObjectMessageEventListener(
183 				fWriter, this));
184 			break;
185 
186 		case B_JSON_ARRAY_START:
187 			SetStackedListenerOnWriter(new BStackedArrayMessageEventListener(
188 				fWriter, this));
189 			break;
190 
191 		default:
192 			HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
193             		"unexpected type of json item to add to container");
194             return false;
195 	}
196 
197 	return ErrorStatus() == B_OK;
198 }
199 
200 
201 void
202 BStackedMessageEventListener::HandleError(status_t status, int32 line,
203 	const char* message)
204 {
205 	fWriter->HandleError(status, line, message);
206 }
207 
208 
209 void
210 BStackedMessageEventListener::Complete()
211 {
212 	// illegal state.
213 	HandleError(JSON_EVENT_LISTENER_ANY_LINE, B_NOT_ALLOWED,
214 		"Complete() called on stacked message listener");
215 }
216 
217 
218 void
219 BStackedMessageEventListener::AddMessage(BMessage* message)
220 {
221 	if (WillAdd()) {
222 		fMessage->AddMessage(NextItemName(), message);
223 		DidAdd();
224 	}
225 }
226 
227 
228 status_t
229 BStackedMessageEventListener::ErrorStatus()
230 {
231 	return fWriter->ErrorStatus();
232 }
233 
234 
235 BStackedMessageEventListener*
236 BStackedMessageEventListener::Parent()
237 {
238 	return fParent;
239 }
240 
241 
242 void
243 BStackedMessageEventListener::AddBool(bool value)
244 {
245 	if (WillAdd()) {
246 		fMessage->AddBool(NextItemName(), value);
247 		DidAdd();
248 	}
249 }
250 
251 void
252 BStackedMessageEventListener::AddNull()
253 {
254 	if (WillAdd()) {
255 		fMessage->AddPointer(NextItemName(), (void*)NULL);
256 		DidAdd();
257 	}
258 }
259 
260 void
261 BStackedMessageEventListener::AddDouble(double value)
262 {
263 	if (WillAdd()) {
264 		fMessage->AddDouble(NextItemName(), value);
265 		DidAdd();
266 	}
267 }
268 
269 void
270 BStackedMessageEventListener::AddString(const char* value)
271 {
272 	if (WillAdd()) {
273 		fMessage->AddString(NextItemName(), value);
274 		DidAdd();
275 	}
276 }
277 
278 
279 bool
280 BStackedMessageEventListener::WillAdd()
281 {
282 	return true;
283 }
284 
285 
286 void
287 BStackedMessageEventListener::DidAdd()
288 {
289 	// noop - present for overriding
290 }
291 
292 
293 void
294 BStackedMessageEventListener::SetStackedListenerOnWriter(
295 	BStackedMessageEventListener* stackedListener)
296 {
297 	fWriter->SetStackedListener(stackedListener);
298 }
299 
300 
301 // #pragma mark - BStackedArrayMessageEventListener
302 
303 
304 BStackedArrayMessageEventListener::BStackedArrayMessageEventListener(
305 	BJsonMessageWriter* writer,
306 	BStackedMessageEventListener* parent)
307 	: BStackedMessageEventListener(writer, parent, B_JSON_MESSAGE_WHAT_ARRAY)
308 {
309 	fCount = 0;
310 }
311 
312 
313 BStackedArrayMessageEventListener::BStackedArrayMessageEventListener(
314 	BJsonMessageWriter* writer,
315 	BStackedMessageEventListener* parent,
316 	BMessage* message)
317 	: BStackedMessageEventListener(writer, parent, message)
318 {
319 	message->what = B_JSON_MESSAGE_WHAT_ARRAY;
320 	fCount = 0;
321 }
322 
323 
324 BStackedArrayMessageEventListener::~BStackedArrayMessageEventListener()
325 {
326 }
327 
328 
329 bool
330 BStackedArrayMessageEventListener::Handle(const BJsonEvent& event)
331 {
332 	if (fWriter->ErrorStatus() != B_OK)
333 		return false;
334 
335 	switch (event.EventType()) {
336 		case B_JSON_ARRAY_END:
337 			if (fParent != NULL)
338 				fParent->AddMessage(fMessage);
339 			SetStackedListenerOnWriter(fParent);
340 			delete this;
341 			break;
342 
343 		default:
344 			return BStackedMessageEventListener::Handle(event);
345 	}
346 
347 	return true;
348 }
349 
350 
351 const char*
352 BStackedArrayMessageEventListener::NextItemName()
353 {
354 	fNextItemName.SetToFormat("%" B_PRIu32, fCount);
355 	return fNextItemName.String();
356 }
357 
358 
359 void
360 BStackedArrayMessageEventListener::DidAdd()
361 {
362 	BStackedMessageEventListener::DidAdd();
363 	fCount++;
364 }
365 
366 
367 // #pragma mark - BStackedObjectMessageEventListener
368 
369 
370 BStackedObjectMessageEventListener::BStackedObjectMessageEventListener(
371 	BJsonMessageWriter* writer,
372 	BStackedMessageEventListener* parent)
373 	: BStackedMessageEventListener(writer, parent, B_JSON_MESSAGE_WHAT_OBJECT)
374 {
375 }
376 
377 
378 BStackedObjectMessageEventListener::BStackedObjectMessageEventListener(
379 	BJsonMessageWriter* writer,
380 	BStackedMessageEventListener* parent,
381 	BMessage* message)
382 	: BStackedMessageEventListener(writer, parent, message)
383 {
384 	message->what = B_JSON_MESSAGE_WHAT_OBJECT;
385 }
386 
387 
388 BStackedObjectMessageEventListener::~BStackedObjectMessageEventListener()
389 {
390 }
391 
392 
393 bool
394 BStackedObjectMessageEventListener::Handle(const BJsonEvent& event)
395 {
396 	if (fWriter->ErrorStatus() != B_OK)
397 		return false;
398 
399 	switch (event.EventType()) {
400 		case B_JSON_OBJECT_END:
401 			if (fParent != NULL)
402 				fParent->AddMessage(fMessage);
403 			SetStackedListenerOnWriter(fParent);
404 			delete this;
405 			break;
406 
407 		case B_JSON_OBJECT_NAME:
408 			fNextItemName.SetTo(event.Content());
409 			break;
410 
411 		default:
412 			return BStackedMessageEventListener::Handle(event);
413 	}
414 
415 	return true;
416 }
417 
418 
419 const char*
420 BStackedObjectMessageEventListener::NextItemName()
421 {
422 	return fNextItemName.String();
423 }
424 
425 
426 bool
427 BStackedObjectMessageEventListener::WillAdd()
428 {
429 	if (0 == fNextItemName.Length()) {
430 		HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
431 				"missing name for adding value into an object");
432 		return false;
433 	}
434 
435 	return true;
436 }
437 
438 
439 void
440 BStackedObjectMessageEventListener::DidAdd()
441 {
442 	BStackedMessageEventListener::DidAdd();
443 	fNextItemName.SetTo("", 0);
444 }
445 
446 
447 // #pragma mark - BJsonMessageWriter
448 
449 
450 BJsonMessageWriter::BJsonMessageWriter(BMessage& message)
451 {
452 	fTopLevelMessage = &message;
453 	fStackedListener = NULL;
454 }
455 
456 
457 BJsonMessageWriter::~BJsonMessageWriter()
458 {
459 	BStackedMessageEventListener* listener = fStackedListener;
460 
461 	while (listener != NULL) {
462 		BStackedMessageEventListener* nextListener = listener->Parent();
463 		delete listener;
464 		listener = nextListener;
465 	}
466 
467 	fStackedListener = NULL;
468 }
469 
470 
471 bool
472 BJsonMessageWriter::Handle(const BJsonEvent& event)
473 {
474 	if (fErrorStatus != B_OK)
475 		return false;
476 
477 	if (fStackedListener != NULL)
478 		return fStackedListener->Handle(event);
479 	else {
480 		switch(event.EventType()) {
481 			case B_JSON_OBJECT_START:
482 				SetStackedListener(new BStackedObjectMessageEventListener(
483 					this, NULL, fTopLevelMessage));
484 				break;
485 
486 			case B_JSON_ARRAY_START:
487 				fTopLevelMessage->what = B_JSON_MESSAGE_WHAT_ARRAY;
488 				SetStackedListener(new BStackedArrayMessageEventListener(
489 					this, NULL, fTopLevelMessage));
490 				break;
491 
492 			default:
493 				HandleError(B_NOT_ALLOWED, JSON_EVENT_LISTENER_ANY_LINE,
494 					"a message object can only handle an object or an array"
495 					"at the top level");
496 				return false;
497 
498 		}
499 	}
500 
501 	return true; // keep going
502 }
503 
504 
505 void
506 BJsonMessageWriter::Complete()
507 {
508 	if (fStackedListener != NULL) {
509 		HandleError(B_BAD_DATA, JSON_EVENT_LISTENER_ANY_LINE,
510 			"unexpected end of input data processing structure");
511 	}
512 }
513 
514 
515 void
516 BJsonMessageWriter::SetStackedListener(
517 	BStackedMessageEventListener* listener)
518 {
519 	fStackedListener = listener;
520 }