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