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_(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 91 private: 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 101 struct picture_header { 102 int32 magic1; // version ? 103 int32 magic2; // endianess ? 104 }; 105 106 107 BPicture::BPicture() 108 : 109 fToken(-1), 110 fExtent(NULL), 111 fUsurped(NULL) 112 { 113 _InitData(); 114 } 115 116 117 BPicture::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 151 BPicture::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 202 BPicture::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 210 void 211 BPicture::_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 223 BPicture::~BPicture() 224 { 225 BAutolock _(sPictureListLock); 226 sPictureList.RemoveItem(this, false); 227 _DisposeData(); 228 } 229 230 231 void 232 BPicture::_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 248 BArchivable* 249 BPicture::Instantiate(BMessage* data) 250 { 251 if (validate_instantiation(data, "BPicture")) 252 return new BPicture(data); 253 254 return NULL; 255 } 256 257 258 status_t 259 BPicture::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 296 status_t 297 BPicture::Perform(perform_code code, void* arg) 298 { 299 return BArchivable::Perform(code, arg); 300 } 301 302 303 status_t 304 BPicture::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 316 status_t 317 BPicture::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 336 status_t 337 BPicture::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 367 void 368 BPicture::_ImportOldData(const void* data, int32 size) 369 { 370 // TODO: We don't support old data for now 371 } 372 373 374 void 375 BPicture::SetToken(int32 token) 376 { 377 fToken = token; 378 } 379 380 381 int32 382 BPicture::Token() const 383 { 384 return fToken; 385 } 386 387 388 bool 389 BPicture::_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 401 bool 402 BPicture::_AssertOldLocalCopy() 403 { 404 // TODO: We don't support old data for now 405 406 return false; 407 } 408 409 410 bool 411 BPicture::_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 428 status_t 429 BPicture::_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 459 status_t 460 BPicture::_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 493 const void* 494 BPicture::Data() const 495 { 496 if (fExtent->Data() == NULL) 497 const_cast<BPicture*>(this)->_AssertLocalCopy(); 498 499 return fExtent->Data(); 500 } 501 502 503 int32 504 BPicture::DataSize() const 505 { 506 if (fExtent->Data() == NULL) 507 const_cast<BPicture*>(this)->_AssertLocalCopy(); 508 509 return fExtent->Size(); 510 } 511 512 513 void 514 BPicture::Usurp(BPicture* lameDuck) 515 { 516 _DisposeData(); 517 518 // Reinitializes the BPicture 519 _InitData(); 520 521 // Do the Usurping 522 fUsurped = lameDuck; 523 } 524 525 526 BPicture* 527 BPicture::StepDown() 528 { 529 BPicture* lameDuck = fUsurped; 530 fUsurped = NULL; 531 532 return lameDuck; 533 } 534 535 536 void BPicture::_ReservedPicture1() {} 537 void BPicture::_ReservedPicture2() {} 538 void BPicture::_ReservedPicture3() {} 539 540 541 BPicture& 542 BPicture::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 566 status_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 583 status_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 633 status_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 668 status_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