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