2 * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>
3 * Distributed under the terms of the MIT License.
7 #include "JsonMessageWriter.h"
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.
18 class BStackedMessageEventListener
: public BJsonEventListener
{
20 BStackedMessageEventListener(
21 BJsonMessageWriter
* writer
,
22 BStackedMessageEventListener
* parent
,
24 BStackedMessageEventListener(
25 BJsonMessageWriter
* writer
,
26 BStackedMessageEventListener
* parent
,
28 ~BStackedMessageEventListener();
30 bool Handle(const BJsonEvent
& event
);
31 void HandleError(status_t status
, int32 line
,
35 void AddMessage(BMessage
* value
);
37 status_t
ErrorStatus();
38 virtual const char* NextItemName() = 0;
40 BStackedMessageEventListener
*
44 void AddBool(bool value
);
46 void AddDouble(double value
);
47 void AddString(const char* value
);
49 virtual bool WillAdd();
50 virtual void DidAdd();
52 void SetStackedListenerOnWriter(
53 BStackedMessageEventListener
*
56 BJsonMessageWriter
* fWriter
;
58 BStackedMessageEventListener
64 class BStackedArrayMessageEventListener
: public BStackedMessageEventListener
{
66 BStackedArrayMessageEventListener(
67 BJsonMessageWriter
* writer
,
68 BStackedMessageEventListener
* parent
);
69 BStackedArrayMessageEventListener(
70 BJsonMessageWriter
* writer
,
71 BStackedMessageEventListener
* parent
,
73 ~BStackedArrayMessageEventListener();
75 bool Handle(const BJsonEvent
& event
);
77 const char* NextItemName();
84 BString fNextItemName
;
89 class BStackedObjectMessageEventListener
: public BStackedMessageEventListener
{
91 BStackedObjectMessageEventListener(
92 BJsonMessageWriter
* writer
,
93 BStackedMessageEventListener
* parent
);
94 BStackedObjectMessageEventListener(
95 BJsonMessageWriter
* writer
,
96 BStackedMessageEventListener
* parent
,
98 ~BStackedObjectMessageEventListener();
100 bool Handle(const BJsonEvent
& event
);
102 const char* NextItemName();
108 BString fNextItemName
;
111 } // namespace BPrivate
113 using BPrivate::BStackedMessageEventListener
;
114 using BPrivate::BStackedArrayMessageEventListener
;
115 using BPrivate::BStackedObjectMessageEventListener
;
118 // #pragma mark - BStackedMessageEventListener
121 BStackedMessageEventListener::BStackedMessageEventListener(
122 BJsonMessageWriter
* writer
,
123 BStackedMessageEventListener
* parent
,
129 fMessage
= new BMessage(messageWhat
);
133 BStackedMessageEventListener::BStackedMessageEventListener(
134 BJsonMessageWriter
* writer
,
135 BStackedMessageEventListener
* parent
,
140 fOwnsMessage
= false;
145 BStackedMessageEventListener::~BStackedMessageEventListener()
153 BStackedMessageEventListener::Handle(const BJsonEvent
& event
)
155 if (fWriter
->ErrorStatus() != B_OK
)
158 switch (event
.EventType()) {
161 AddDouble(event
.ContentDouble());
165 AddString(event
.Content());
180 case B_JSON_OBJECT_START
:
182 SetStackedListenerOnWriter(new BStackedObjectMessageEventListener(
187 case B_JSON_ARRAY_START
:
189 SetStackedListenerOnWriter(new BStackedArrayMessageEventListener(
196 HandleError(B_NOT_ALLOWED
, JSON_EVENT_LISTENER_ANY_LINE
,
197 "unexpected type of json item to add to container");
202 return ErrorStatus() == B_OK
;
207 BStackedMessageEventListener::HandleError(status_t status
, int32 line
,
210 fWriter
->HandleError(status
, line
, message
);
215 BStackedMessageEventListener::Complete()
218 HandleError(JSON_EVENT_LISTENER_ANY_LINE
, B_NOT_ALLOWED
,
219 "Complete() called on stacked message listener");
224 BStackedMessageEventListener::AddMessage(BMessage
* message
)
227 fMessage
->AddMessage(NextItemName(), message
);
234 BStackedMessageEventListener::ErrorStatus()
236 return fWriter
->ErrorStatus();
240 BStackedMessageEventListener
*
241 BStackedMessageEventListener::Parent()
248 BStackedMessageEventListener::AddBool(bool value
)
251 fMessage
->AddBool(NextItemName(), value
);
257 BStackedMessageEventListener::AddNull()
260 fMessage
->AddPointer(NextItemName(), (void*)NULL
);
266 BStackedMessageEventListener::AddDouble(double value
)
269 fMessage
->AddDouble(NextItemName(), value
);
275 BStackedMessageEventListener::AddString(const char* value
)
278 fMessage
->AddString(NextItemName(), value
);
285 BStackedMessageEventListener::WillAdd()
292 BStackedMessageEventListener::DidAdd()
294 // noop - present for overriding
299 BStackedMessageEventListener::SetStackedListenerOnWriter(
300 BStackedMessageEventListener
* stackedListener
)
302 fWriter
->SetStackedListener(stackedListener
);
306 // #pragma mark - BStackedArrayMessageEventListener
309 BStackedArrayMessageEventListener::BStackedArrayMessageEventListener(
310 BJsonMessageWriter
* writer
,
311 BStackedMessageEventListener
* parent
)
313 BStackedMessageEventListener(writer
, parent
, B_JSON_MESSAGE_WHAT_ARRAY
)
319 BStackedArrayMessageEventListener::BStackedArrayMessageEventListener(
320 BJsonMessageWriter
* writer
,
321 BStackedMessageEventListener
* parent
,
324 BStackedMessageEventListener(writer
, parent
, message
)
326 message
->what
= B_JSON_MESSAGE_WHAT_ARRAY
;
331 BStackedArrayMessageEventListener::~BStackedArrayMessageEventListener()
337 BStackedArrayMessageEventListener::Handle(const BJsonEvent
& event
)
339 if (fWriter
->ErrorStatus() != B_OK
)
342 switch (event
.EventType()) {
343 case B_JSON_ARRAY_END
:
346 fParent
->AddMessage(fMessage
);
347 SetStackedListenerOnWriter(fParent
);
353 return BStackedMessageEventListener::Handle(event
);
361 BStackedArrayMessageEventListener::NextItemName()
363 fNextItemName
.SetToFormat("%" B_PRIu32
, fCount
);
364 return fNextItemName
.String();
369 BStackedArrayMessageEventListener::DidAdd()
371 BStackedMessageEventListener::DidAdd();
376 // #pragma mark - BStackedObjectMessageEventListener
379 BStackedObjectMessageEventListener::BStackedObjectMessageEventListener(
380 BJsonMessageWriter
* writer
,
381 BStackedMessageEventListener
* parent
)
383 BStackedMessageEventListener(writer
, parent
, B_JSON_MESSAGE_WHAT_OBJECT
)
388 BStackedObjectMessageEventListener::BStackedObjectMessageEventListener(
389 BJsonMessageWriter
* writer
,
390 BStackedMessageEventListener
* parent
,
393 BStackedMessageEventListener(writer
, parent
, message
)
395 message
->what
= B_JSON_MESSAGE_WHAT_OBJECT
;
399 BStackedObjectMessageEventListener::~BStackedObjectMessageEventListener()
405 BStackedObjectMessageEventListener::Handle(const BJsonEvent
& event
)
407 if (fWriter
->ErrorStatus() != B_OK
)
410 switch (event
.EventType()) {
411 case B_JSON_OBJECT_END
:
414 fParent
->AddMessage(fMessage
);
415 SetStackedListenerOnWriter(fParent
);
420 case B_JSON_OBJECT_NAME
:
421 fNextItemName
.SetTo(event
.Content());
425 return BStackedMessageEventListener::Handle(event
);
433 BStackedObjectMessageEventListener::NextItemName()
435 return fNextItemName
.String();
440 BStackedObjectMessageEventListener::WillAdd()
442 if (0 == fNextItemName
.Length()) {
443 HandleError(B_NOT_ALLOWED
, JSON_EVENT_LISTENER_ANY_LINE
,
444 "missing name for adding value into an object");
453 BStackedObjectMessageEventListener::DidAdd()
455 BStackedMessageEventListener::DidAdd();
456 fNextItemName
.SetTo("", 0);
460 // #pragma mark - BJsonMessageWriter
463 BJsonMessageWriter::BJsonMessageWriter(BMessage
& message
)
465 fTopLevelMessage
= &message
;
466 fStackedListener
= NULL
;
470 BJsonMessageWriter::~BJsonMessageWriter()
472 BStackedMessageEventListener
* listener
= fStackedListener
;
474 while (listener
!= NULL
) {
475 BStackedMessageEventListener
* nextListener
= listener
->Parent();
477 listener
= nextListener
;
480 fStackedListener
= NULL
;
485 BJsonMessageWriter::Handle(const BJsonEvent
& event
)
487 if (fErrorStatus
!= B_OK
)
490 if (fStackedListener
!= NULL
)
491 return fStackedListener
->Handle(event
);
493 switch(event
.EventType()) {
494 case B_JSON_OBJECT_START
:
496 SetStackedListener(new BStackedObjectMessageEventListener(
497 this, NULL
, fTopLevelMessage
));
501 case B_JSON_ARRAY_START
:
503 fTopLevelMessage
->what
= B_JSON_MESSAGE_WHAT_ARRAY
;
504 SetStackedListener(new BStackedArrayMessageEventListener(
505 this, NULL
, fTopLevelMessage
));
511 HandleError(B_NOT_ALLOWED
, JSON_EVENT_LISTENER_ANY_LINE
,
512 "a message object can only handle an object or an array"
519 return true; // keep going
524 BJsonMessageWriter::Complete()
526 if (fStackedListener
!= NULL
) {
527 HandleError(B_BAD_DATA
, JSON_EVENT_LISTENER_ANY_LINE
,
528 "unexpected end of input data processing structure");
534 BJsonMessageWriter::SetStackedListener(
535 BStackedMessageEventListener
* listener
)
537 fStackedListener
= listener
;