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