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 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 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 145 BStackedMessageEventListener::~BStackedMessageEventListener() 146 { 147 if (fOwnsMessage) 148 delete fMessage; 149 } 150 151 152 bool 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 207 BStackedMessageEventListener::HandleError(status_t status, int32 line, 208 const char* message) 209 { 210 fWriter->HandleError(status, line, message); 211 } 212 213 214 void 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 224 BStackedMessageEventListener::AddMessage(BMessage* message) 225 { 226 if (WillAdd()) { 227 fMessage->AddMessage(NextItemName(), message); 228 DidAdd(); 229 } 230 } 231 232 233 status_t 234 BStackedMessageEventListener::ErrorStatus() 235 { 236 return fWriter->ErrorStatus(); 237 } 238 239 240 BStackedMessageEventListener* 241 BStackedMessageEventListener::Parent() 242 { 243 return fParent; 244 } 245 246 247 void 248 BStackedMessageEventListener::AddBool(bool value) 249 { 250 if (WillAdd()) { 251 fMessage->AddBool(NextItemName(), value); 252 DidAdd(); 253 } 254 } 255 256 void 257 BStackedMessageEventListener::AddNull() 258 { 259 if (WillAdd()) { 260 fMessage->AddPointer(NextItemName(), (void*)NULL); 261 DidAdd(); 262 } 263 } 264 265 void 266 BStackedMessageEventListener::AddDouble(double value) 267 { 268 if (WillAdd()) { 269 fMessage->AddDouble(NextItemName(), value); 270 DidAdd(); 271 } 272 } 273 274 void 275 BStackedMessageEventListener::AddString(const char* value) 276 { 277 if (WillAdd()) { 278 fMessage->AddString(NextItemName(), value); 279 DidAdd(); 280 } 281 } 282 283 284 bool 285 BStackedMessageEventListener::WillAdd() 286 { 287 return true; 288 } 289 290 291 void 292 BStackedMessageEventListener::DidAdd() 293 { 294 // noop - present for overriding 295 } 296 297 298 void 299 BStackedMessageEventListener::SetStackedListenerOnWriter( 300 BStackedMessageEventListener* stackedListener) 301 { 302 fWriter->SetStackedListener(stackedListener); 303 } 304 305 306 // #pragma mark - BStackedArrayMessageEventListener 307 308 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 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 331 BStackedArrayMessageEventListener::~BStackedArrayMessageEventListener() 332 { 333 } 334 335 336 bool 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* 361 BStackedArrayMessageEventListener::NextItemName() 362 { 363 fNextItemName.SetToFormat("%" B_PRIu32, fCount); 364 return fNextItemName.String(); 365 } 366 367 368 void 369 BStackedArrayMessageEventListener::DidAdd() 370 { 371 BStackedMessageEventListener::DidAdd(); 372 fCount++; 373 } 374 375 376 // #pragma mark - BStackedObjectMessageEventListener 377 378 379 BStackedObjectMessageEventListener::BStackedObjectMessageEventListener( 380 BJsonMessageWriter* writer, 381 BStackedMessageEventListener* parent) 382 : 383 BStackedMessageEventListener(writer, parent, B_JSON_MESSAGE_WHAT_OBJECT) 384 { 385 } 386 387 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 399 BStackedObjectMessageEventListener::~BStackedObjectMessageEventListener() 400 { 401 } 402 403 404 bool 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* 433 BStackedObjectMessageEventListener::NextItemName() 434 { 435 return fNextItemName.String(); 436 } 437 438 439 bool 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 453 BStackedObjectMessageEventListener::DidAdd() 454 { 455 BStackedMessageEventListener::DidAdd(); 456 fNextItemName.SetTo("", 0); 457 } 458 459 460 // #pragma mark - BJsonMessageWriter 461 462 463 BJsonMessageWriter::BJsonMessageWriter(BMessage& message) 464 { 465 fTopLevelMessage = &message; 466 fStackedListener = NULL; 467 } 468 469 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 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 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 534 BJsonMessageWriter::SetStackedListener( 535 BStackedMessageEventListener* listener) 536 { 537 fStackedListener = listener; 538 }