1 /* 2 * Copyright 2001-2014 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers, mflerackers@androme.be 7 */ 8 9 10 // Records a series of drawing instructions that can be "replayed" later. 11 12 13 #include <Picture.h> 14 15 #include <new> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string.h> 19 20 //#define DEBUG 1 21 #include <ByteOrder.h> 22 #include <Debug.h> 23 #include <List.h> 24 #include <Message.h> 25 26 #include <AppServerLink.h> 27 #include <Autolock.h> 28 #include <ObjectList.h> 29 #include <PicturePlayer.h> 30 #include <ServerProtocol.h> 31 32 #include "PicturePrivate.h" 33 34 35 static BObjectList<BPicture> sPictureList; 36 static BLocker sPictureListLock; 37 38 39 void 40 reconnect_pictures_to_app_server() 41 { 42 BAutolock _(sPictureListLock); 43 for (int32 i = 0; i < sPictureList.CountItems(); i++) { 44 BPicture::Private picture(sPictureList.ItemAt(i)); 45 picture.ReconnectToAppServer(); 46 } 47 } 48 49 50 BPicture::Private::Private(BPicture* picture) 51 : 52 fPicture(picture) 53 { 54 } 55 56 57 void 58 BPicture::Private::ReconnectToAppServer() 59 { 60 fPicture->_Upload(); 61 } 62 63 64 struct _BPictureExtent_ { 65 _BPictureExtent_(const int32& size = 0); 66 ~_BPictureExtent_(); 67 68 const void* Data() const { return fNewData; } 69 status_t ImportData(const void* data, 70 const int32& size); 71 72 status_t Flatten(BDataIO* stream); 73 status_t Unflatten(BDataIO* stream); 74 75 int32 Size() const { return fNewSize; } 76 status_t SetSize(const int32& size); 77 78 bool AddPicture(BPicture* picture) 79 { return fPictures.AddItem(picture); } 80 void DeletePicture(const int32& index) 81 { delete static_cast<BPicture*> 82 (fPictures.RemoveItem(index)); } 83 84 BList* Pictures() { return &fPictures; } 85 BPicture* PictureAt(const int32& index) 86 { return static_cast<BPicture*> 87 (fPictures.ItemAt(index)); } 88 89 int32 CountPictures() const 90 { return fPictures.CountItems(); } 91 92 private: 93 void* fNewData; 94 int32 fNewSize; 95 96 BList fPictures; 97 // In R5 this is a BArray<BPicture*> 98 // which is completely inline. 99 }; 100 101 102 struct picture_header { 103 int32 magic1; // version ? 104 int32 magic2; // endianess ? 105 }; 106 107 108 BPicture::BPicture() 109 : 110 fToken(-1), 111 fExtent(NULL), 112 fUsurped(NULL) 113 { 114 _InitData(); 115 } 116 117 118 BPicture::BPicture(const BPicture& otherPicture) 119 : 120 fToken(-1), 121 fExtent(NULL), 122 fUsurped(NULL) 123 { 124 _InitData(); 125 126 if (otherPicture.fToken != -1) { 127 BPrivate::AppServerLink link; 128 link.StartMessage(AS_CLONE_PICTURE); 129 link.Attach<int32>(otherPicture.fToken); 130 131 status_t status = B_ERROR; 132 if (link.FlushWithReply(status) == B_OK && status == B_OK) 133 link.Read<int32>(&fToken); 134 135 if (status < B_OK) 136 return; 137 } 138 139 if (otherPicture.fExtent->Size() > 0) { 140 fExtent->ImportData(otherPicture.fExtent->Data(), 141 otherPicture.fExtent->Size()); 142 143 for (int32 i = 0; i < otherPicture.fExtent->CountPictures(); i++) { 144 BPicture* picture 145 = new BPicture(*otherPicture.fExtent->PictureAt(i)); 146 fExtent->AddPicture(picture); 147 } 148 } 149 } 150 151 152 BPicture::BPicture(BMessage* data) 153 : 154 fToken(-1), 155 fExtent(NULL), 156 fUsurped(NULL) 157 { 158 _InitData(); 159 160 int32 version; 161 if (data->FindInt32("_ver", &version) != B_OK) 162 version = 0; 163 164 int8 endian; 165 if (data->FindInt8("_endian", &endian) != B_OK) 166 endian = 0; 167 168 const void* pictureData; 169 int32 size; 170 if (data->FindData("_data", B_RAW_TYPE, &pictureData, (ssize_t*)&size) 171 != B_OK) { 172 return; 173 } 174 175 // Load sub pictures 176 BMessage pictureMessage; 177 int32 i = 0; 178 while (data->FindMessage("piclib", i++, &pictureMessage) == B_OK) { 179 BPicture* picture = new BPicture(&pictureMessage); 180 fExtent->AddPicture(picture); 181 } 182 183 if (version == 0) { 184 // TODO: For now. We'll see if it's worth to support old style data 185 debugger("old style BPicture data is not supported"); 186 } else if (version == 1) { 187 fExtent->ImportData(data, size); 188 189 // swap_data(fExtent->fNewData, fExtent->fNewSize); 190 191 if (fExtent->Size() > 0) 192 _AssertServerCopy(); 193 } 194 195 // Do we just free the data now? 196 if (fExtent->Size() > 0) 197 fExtent->SetSize(0); 198 199 // What with the sub pictures? 200 for (i = fExtent->CountPictures() - 1; i >= 0; i--) 201 fExtent->DeletePicture(i); 202 } 203 204 205 BPicture::BPicture(const void* data, int32 size) 206 { 207 _InitData(); 208 // TODO: For now. We'll see if it's worth to support old style data 209 debugger("old style BPicture data is not supported"); 210 } 211 212 213 void 214 BPicture::_InitData() 215 { 216 fToken = -1; 217 fUsurped = NULL; 218 219 fExtent = new (std::nothrow) _BPictureExtent_; 220 221 BAutolock _(sPictureListLock); 222 sPictureList.AddItem(this); 223 } 224 225 226 BPicture::~BPicture() 227 { 228 BAutolock _(sPictureListLock); 229 sPictureList.RemoveItem(this); 230 _DisposeData(); 231 } 232 233 234 void 235 BPicture::_DisposeData() 236 { 237 if (fToken != -1) { 238 BPrivate::AppServerLink link; 239 240 link.StartMessage(AS_DELETE_PICTURE); 241 link.Attach<int32>(fToken); 242 link.Flush(); 243 SetToken(-1); 244 } 245 246 delete fExtent; 247 fExtent = NULL; 248 } 249 250 251 BArchivable* 252 BPicture::Instantiate(BMessage* data) 253 { 254 if (validate_instantiation(data, "BPicture")) 255 return new BPicture(data); 256 257 return NULL; 258 } 259 260 261 status_t 262 BPicture::Archive(BMessage* data, bool deep) const 263 { 264 if (!const_cast<BPicture*>(this)->_AssertLocalCopy()) 265 return B_ERROR; 266 267 status_t err = BArchivable::Archive(data, deep); 268 if (err != B_OK) 269 return err; 270 271 err = data->AddInt32("_ver", 1); 272 if (err != B_OK) 273 return err; 274 275 err = data->AddInt8("_endian", B_HOST_IS_BENDIAN); 276 if (err != B_OK) 277 return err; 278 279 err = data->AddData("_data", B_RAW_TYPE, fExtent->Data(), fExtent->Size()); 280 if (err != B_OK) 281 return err; 282 283 for (int32 i = 0; i < fExtent->CountPictures(); i++) { 284 BMessage pictureMessage; 285 286 err = fExtent->PictureAt(i)->Archive(&pictureMessage, deep); 287 if (err != B_OK) 288 break; 289 290 err = data->AddMessage("piclib", &pictureMessage); 291 if (err != B_OK) 292 break; 293 } 294 295 return err; 296 } 297 298 299 status_t 300 BPicture::Perform(perform_code code, void* arg) 301 { 302 return BArchivable::Perform(code, arg); 303 } 304 305 306 status_t 307 BPicture::Play(void** callBackTable, int32 tableEntries, void* user) 308 { 309 if (!_AssertLocalCopy()) 310 return B_ERROR; 311 312 BPrivate::PicturePlayer player(fExtent->Data(), fExtent->Size(), 313 fExtent->Pictures()); 314 315 return player.Play(callBackTable, tableEntries, user); 316 } 317 318 319 status_t 320 BPicture::Flatten(BDataIO* stream) 321 { 322 // TODO: what about endianess? 323 324 if (!_AssertLocalCopy()) 325 return B_ERROR; 326 327 const picture_header header = { 2, 0 }; 328 ssize_t bytesWritten = stream->Write(&header, sizeof(header)); 329 if (bytesWritten < B_OK) 330 return bytesWritten; 331 332 if (bytesWritten != (ssize_t)sizeof(header)) 333 return B_IO_ERROR; 334 335 return fExtent->Flatten(stream); 336 } 337 338 339 status_t 340 BPicture::Unflatten(BDataIO* stream) 341 { 342 // TODO: clear current picture data? 343 344 picture_header header; 345 ssize_t bytesRead = stream->Read(&header, sizeof(header)); 346 if (bytesRead < B_OK) 347 return bytesRead; 348 349 if (bytesRead != (ssize_t)sizeof(header) 350 || header.magic1 != 2 || header.magic2 != 0) 351 return B_BAD_TYPE; 352 353 status_t status = fExtent->Unflatten(stream); 354 if (status < B_OK) 355 return status; 356 357 // swap_data(fExtent->fNewData, fExtent->fNewSize); 358 359 if (!_AssertServerCopy()) 360 return B_ERROR; 361 362 // Data is now kept server side, remove the local copy 363 if (fExtent->Data() != NULL) 364 fExtent->SetSize(0); 365 366 return status; 367 } 368 369 370 void 371 BPicture::_ImportOldData(const void* data, int32 size) 372 { 373 // TODO: We don't support old data for now 374 } 375 376 377 void 378 BPicture::SetToken(int32 token) 379 { 380 fToken = token; 381 } 382 383 384 int32 385 BPicture::Token() const 386 { 387 return fToken; 388 } 389 390 391 bool 392 BPicture::_AssertLocalCopy() 393 { 394 if (fExtent->Data() != NULL) 395 return true; 396 397 if (fToken == -1) 398 return false; 399 400 return _Download() == B_OK; 401 } 402 403 404 bool 405 BPicture::_AssertOldLocalCopy() 406 { 407 // TODO: We don't support old data for now 408 409 return false; 410 } 411 412 413 bool 414 BPicture::_AssertServerCopy() 415 { 416 if (fToken != -1) 417 return true; 418 419 if (fExtent->Data() == NULL) 420 return false; 421 422 for (int32 i = 0; i < fExtent->CountPictures(); i++) { 423 if (!fExtent->PictureAt(i)->_AssertServerCopy()) 424 return false; 425 } 426 427 return _Upload() == B_OK; 428 } 429 430 431 status_t 432 BPicture::_Upload() 433 { 434 if (fExtent == NULL || fExtent->Data() == NULL) 435 return B_BAD_VALUE; 436 437 BPrivate::AppServerLink link; 438 439 link.StartMessage(AS_CREATE_PICTURE); 440 link.Attach<int32>(fExtent->CountPictures()); 441 442 for (int32 i = 0; i < fExtent->CountPictures(); i++) { 443 BPicture* picture = fExtent->PictureAt(i); 444 if (picture != NULL) 445 link.Attach<int32>(picture->fToken); 446 else 447 link.Attach<int32>(-1); 448 } 449 link.Attach<int32>(fExtent->Size()); 450 link.Attach(fExtent->Data(), fExtent->Size()); 451 452 status_t status = B_ERROR; 453 if (link.FlushWithReply(status) == B_OK 454 && status == B_OK) { 455 link.Read<int32>(&fToken); 456 } 457 458 return status; 459 } 460 461 462 status_t 463 BPicture::_Download() 464 { 465 ASSERT(fExtent->Data() == NULL); 466 ASSERT(fToken != -1); 467 468 BPrivate::AppServerLink link; 469 470 link.StartMessage(AS_DOWNLOAD_PICTURE); 471 link.Attach<int32>(fToken); 472 473 status_t status = B_ERROR; 474 if (link.FlushWithReply(status) == B_OK && status == B_OK) { 475 int32 count = 0; 476 link.Read<int32>(&count); 477 478 // Read sub picture tokens 479 for (int32 i = 0; i < count; i++) { 480 BPicture* picture = new BPicture; 481 link.Read<int32>(&picture->fToken); 482 fExtent->AddPicture(picture); 483 } 484 485 int32 size; 486 link.Read<int32>(&size); 487 status = fExtent->SetSize(size); 488 if (status == B_OK) 489 link.Read(const_cast<void*>(fExtent->Data()), size); 490 } 491 492 return status; 493 } 494 495 496 const void* 497 BPicture::Data() const 498 { 499 if (fExtent->Data() == NULL) 500 const_cast<BPicture*>(this)->_AssertLocalCopy(); 501 502 return fExtent->Data(); 503 } 504 505 506 int32 507 BPicture::DataSize() const 508 { 509 if (fExtent->Data() == NULL) 510 const_cast<BPicture*>(this)->_AssertLocalCopy(); 511 512 return fExtent->Size(); 513 } 514 515 516 void 517 BPicture::Usurp(BPicture* lameDuck) 518 { 519 _DisposeData(); 520 521 // Reinitializes the BPicture 522 _InitData(); 523 524 // Do the Usurping 525 fUsurped = lameDuck; 526 } 527 528 529 BPicture* 530 BPicture::StepDown() 531 { 532 BPicture* lameDuck = fUsurped; 533 fUsurped = NULL; 534 535 return lameDuck; 536 } 537 538 539 void BPicture::_ReservedPicture1() {} 540 void BPicture::_ReservedPicture2() {} 541 void BPicture::_ReservedPicture3() {} 542 543 544 BPicture& 545 BPicture::operator=(const BPicture&) 546 { 547 return* this; 548 } 549 550 551 // _BPictureExtent_ 552 _BPictureExtent_::_BPictureExtent_(const int32& size) 553 : 554 fNewData(NULL), 555 fNewSize(0) 556 { 557 SetSize(size); 558 } 559 560 561 _BPictureExtent_::~_BPictureExtent_() 562 { 563 free(fNewData); 564 for (int32 i = 0; i < fPictures.CountItems(); i++) 565 delete static_cast<BPicture*>(fPictures.ItemAtFast(i)); 566 } 567 568 569 status_t 570 _BPictureExtent_::ImportData(const void* data, const int32& size) 571 { 572 if (data == NULL) 573 return B_BAD_VALUE; 574 575 status_t status = B_OK; 576 if (Size() != size) 577 status = SetSize(size); 578 579 if (status == B_OK) 580 memcpy(fNewData, data, size); 581 582 return status; 583 } 584 585 586 status_t 587 _BPictureExtent_::Unflatten(BDataIO* stream) 588 { 589 if (stream == NULL) 590 return B_BAD_VALUE; 591 592 int32 count = 0; 593 ssize_t bytesRead = stream->Read(&count, sizeof(count)); 594 if (bytesRead < B_OK) 595 return bytesRead; 596 if (bytesRead != (ssize_t)sizeof(count)) 597 return B_BAD_DATA; 598 599 for (int32 i = 0; i < count; i++) { 600 BPicture* picture = new BPicture; 601 status_t status = picture->Unflatten(stream); 602 if (status < B_OK) { 603 delete picture; 604 return status; 605 } 606 607 AddPicture(picture); 608 } 609 610 int32 size; 611 bytesRead = stream->Read(&size, sizeof(size)); 612 if (bytesRead < B_OK) 613 return bytesRead; 614 615 if (bytesRead != (ssize_t)sizeof(size)) 616 return B_IO_ERROR; 617 618 status_t status = B_OK; 619 if (Size() != size) 620 status = SetSize(size); 621 622 if (status < B_OK) 623 return status; 624 625 bytesRead = stream->Read(fNewData, size); 626 if (bytesRead < B_OK) 627 return bytesRead; 628 629 if (bytesRead != (ssize_t)size) 630 return B_IO_ERROR; 631 632 return B_OK; 633 } 634 635 636 status_t 637 _BPictureExtent_::Flatten(BDataIO* stream) 638 { 639 int32 count = fPictures.CountItems(); 640 ssize_t bytesWritten = stream->Write(&count, sizeof(count)); 641 if (bytesWritten < B_OK) 642 return bytesWritten; 643 644 if (bytesWritten != (ssize_t)sizeof(count)) 645 return B_IO_ERROR; 646 647 for (int32 i = 0; i < count; i++) { 648 status_t status = PictureAt(i)->Flatten(stream); 649 if (status < B_OK) 650 return status; 651 } 652 653 bytesWritten = stream->Write(&fNewSize, sizeof(fNewSize)); 654 if (bytesWritten < B_OK) 655 return bytesWritten; 656 657 if (bytesWritten != (ssize_t)sizeof(fNewSize)) 658 return B_IO_ERROR; 659 660 bytesWritten = stream->Write(fNewData, fNewSize); 661 if (bytesWritten < B_OK) 662 return bytesWritten; 663 664 if (bytesWritten != fNewSize) 665 return B_IO_ERROR; 666 667 return B_OK; 668 } 669 670 671 status_t 672 _BPictureExtent_::SetSize(const int32& size) 673 { 674 if (size < 0) 675 return B_BAD_VALUE; 676 677 if (size == fNewSize) 678 return B_OK; 679 680 if (size == 0) { 681 free(fNewData); 682 fNewData = NULL; 683 } else { 684 void* data = realloc(fNewData, size); 685 if (data == NULL) 686 return B_NO_MEMORY; 687 688 fNewData = data; 689 } 690 691 fNewSize = size; 692 return B_OK; 693 } 694