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 10namespace 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 18class BStackedMessageEventListener : public BJsonEventListener { 19public: 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 43protected: 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 64class BStackedArrayMessageEventListener : public BStackedMessageEventListener { 65public: 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 79protected: 80 void DidAdd(); 81 82private: 83 uint32 fCount; 84 BString fNextItemName; 85 86}; 87 88 89class BStackedObjectMessageEventListener : public BStackedMessageEventListener { 90public: 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 104protected: 105 bool WillAdd(); 106 void DidAdd(); 107private: 108 BString fNextItemName; 109}; 110 111} // namespace BPrivate 112 113using BPrivate::BStackedMessageEventListener; 114using BPrivate::BStackedArrayMessageEventListener; 115using BPrivate::BStackedObjectMessageEventListener; 116 117 118// #pragma mark - BStackedMessageEventListener 119 120 121BStackedMessageEventListener::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 133BStackedMessageEventListener::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 145BStackedMessageEventListener::~BStackedMessageEventListener() 146{ 147 if (fOwnsMessage) 148 delete fMessage; 149} 150 151 152bool 153BStackedMessageEventListener::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 206void 207BStackedMessageEventListener::HandleError(status_t status, int32 line, 208 const char* message) 209{ 210 fWriter->HandleError(status, line, message); 211} 212 213 214void 215BStackedMessageEventListener::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 223void 224BStackedMessageEventListener::AddMessage(BMessage* message) 225{ 226 if (WillAdd()) { 227 fMessage->AddMessage(NextItemName(), message); 228 DidAdd(); 229 } 230} 231 232 233status_t 234BStackedMessageEventListener::ErrorStatus() 235{ 236 return fWriter->ErrorStatus(); 237} 238 239 240BStackedMessageEventListener* 241BStackedMessageEventListener::Parent() 242{ 243 return fParent; 244} 245 246 247void 248BStackedMessageEventListener::AddBool(bool value) 249{ 250 if (WillAdd()) { 251 fMessage->AddBool(NextItemName(), value); 252 DidAdd(); 253 } 254} 255 256void 257BStackedMessageEventListener::AddNull() 258{ 259 if (WillAdd()) { 260 fMessage->AddPointer(NextItemName(), (void*)NULL); 261 DidAdd(); 262 } 263} 264 265void 266BStackedMessageEventListener::AddDouble(double value) 267{ 268 if (WillAdd()) { 269 fMessage->AddDouble(NextItemName(), value); 270 DidAdd(); 271 } 272} 273 274void 275BStackedMessageEventListener::AddString(const char* value) 276{ 277 if (WillAdd()) { 278 fMessage->AddString(NextItemName(), value); 279 DidAdd(); 280 } 281} 282 283 284bool 285BStackedMessageEventListener::WillAdd() 286{ 287 return true; 288} 289 290 291void 292BStackedMessageEventListener::DidAdd() 293{ 294 // noop - present for overriding 295} 296 297 298void 299BStackedMessageEventListener::SetStackedListenerOnWriter( 300 BStackedMessageEventListener* stackedListener) 301{ 302 fWriter->SetStackedListener(stackedListener); 303} 304 305 306// #pragma mark - BStackedArrayMessageEventListener 307 308 309BStackedArrayMessageEventListener::BStackedArrayMessageEventListener( 310 BJsonMessageWriter* writer, 311 BStackedMessageEventListener* parent) 312 : 313 BStackedMessageEventListener(writer, parent, B_JSON_MESSAGE_WHAT_ARRAY) 314{ 315 fCount = 0; 316} 317 318 319BStackedArrayMessageEventListener::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 331BStackedArrayMessageEventListener::~BStackedArrayMessageEventListener() 332{ 333} 334 335 336bool 337BStackedArrayMessageEventListener::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 360const char* 361BStackedArrayMessageEventListener::NextItemName() 362{ 363 fNextItemName.SetToFormat("%" B_PRIu32, fCount); 364 return fNextItemName.String(); 365} 366 367 368void 369BStackedArrayMessageEventListener::DidAdd() 370{ 371 BStackedMessageEventListener::DidAdd(); 372 fCount++; 373} 374 375 376// #pragma mark - BStackedObjectMessageEventListener 377 378 379BStackedObjectMessageEventListener::BStackedObjectMessageEventListener( 380 BJsonMessageWriter* writer, 381 BStackedMessageEventListener* parent) 382 : 383 BStackedMessageEventListener(writer, parent, B_JSON_MESSAGE_WHAT_OBJECT) 384{ 385} 386 387 388BStackedObjectMessageEventListener::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 399BStackedObjectMessageEventListener::~BStackedObjectMessageEventListener() 400{ 401} 402 403 404bool 405BStackedObjectMessageEventListener::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 432const char* 433BStackedObjectMessageEventListener::NextItemName() 434{ 435 return fNextItemName.String(); 436} 437 438 439bool 440BStackedObjectMessageEventListener::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 452void 453BStackedObjectMessageEventListener::DidAdd() 454{ 455 BStackedMessageEventListener::DidAdd(); 456 fNextItemName.SetTo("", 0); 457} 458 459 460// #pragma mark - BJsonMessageWriter 461 462 463BJsonMessageWriter::BJsonMessageWriter(BMessage& message) 464{ 465 fTopLevelMessage = &message; 466 fStackedListener = NULL; 467} 468 469 470BJsonMessageWriter::~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 484bool 485BJsonMessageWriter::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 523void 524BJsonMessageWriter::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 533void 534BJsonMessageWriter::SetStackedListener( 535 BStackedMessageEventListener* listener) 536{ 537 fStackedListener = listener; 538}