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