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