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 }