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