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