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 token(-1), 66 extent(NULL), 67 usurped(NULL) 68 { 69 _InitData(); 70 } 71 72 73 BPicture::BPicture(const BPicture &otherPicture) 74 : 75 token(-1), 76 extent(NULL), 77 usurped(NULL) 78 { 79 _InitData(); 80 81 if (otherPicture.token != -1) { 82 BPrivate::AppServerLink link; 83 link.StartMessage(AS_CLONE_PICTURE); 84 link.Attach<int32>(otherPicture.token); 85 86 status_t status = B_ERROR; 87 if (link.FlushWithReply(status) == B_OK 88 && status == B_OK) 89 link.Read<int32>(&token); 90 if (status < B_OK) 91 return; 92 } 93 94 if (otherPicture.extent->Size() > 0) { 95 extent->ImportData(otherPicture.extent->Data(), otherPicture.extent->Size()); 96 97 for (int32 i = 0; i < otherPicture.extent->CountPictures(); i++) { 98 BPicture *picture = new BPicture(*otherPicture.extent->PictureAt(i)); 99 extent->AddPicture(picture); 100 } 101 } 102 } 103 104 105 BPicture::BPicture(BMessage *archive) 106 : 107 token(-1), 108 extent(NULL), 109 usurped(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 extent->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 extent->ImportData(data, size); 139 140 // swap_data(extent->fNewData, extent->fNewSize); 141 142 if (extent->Size() > 0) 143 _AssertServerCopy(); 144 } 145 146 // Do we just free the data now? 147 if (extent->Size() > 0) 148 extent->SetSize(0); 149 150 // What with the sub pictures? 151 for (i = extent->CountPictures() - 1; i >= 0; i--) 152 extent->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 token = -1; 168 usurped = NULL; 169 170 extent = new (std::nothrow) _BPictureExtent_; 171 } 172 173 174 BPicture::~BPicture() 175 { 176 _DisposeData(); 177 } 178 179 180 void 181 BPicture::_DisposeData() 182 { 183 if (token != -1) { 184 BPrivate::AppServerLink link; 185 186 link.StartMessage(AS_DELETE_PICTURE); 187 link.Attach<int32>(token); 188 link.Flush(); 189 SetToken(-1); 190 } 191 192 delete extent; 193 extent = 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, extent->Data(), extent->Size()); 226 if (err != B_OK) 227 return err; 228 229 for (int32 i = 0; i < extent->CountPictures(); i++) { 230 BMessage picMsg; 231 232 extent->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(extent->Data(), extent->Size(), extent->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 = extent->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 = extent->PictureAt(i)->Flatten(stream); 285 if (status < B_OK) 286 return status; 287 } 288 289 int32 size = extent->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(extent->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 extent->AddPicture(picture); 333 } 334 335 status_t status = extent->ImportData(stream); 336 if (status < B_OK) 337 return status; 338 339 // swap_data(extent->fNewData, extent->fNewSize); 340 341 if (!_AssertServerCopy()) 342 return B_ERROR; 343 344 // Data is now kept server side, remove the local copy 345 if (extent->Data() != NULL) 346 extent->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]->token); 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>(&token);*/ 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 token = _token; 390 } 391 392 393 bool 394 BPicture::_AssertLocalCopy() 395 { 396 if (extent->Data() != NULL) 397 return true; 398 399 if (token == -1) 400 return false; 401 402 return _Download() == B_OK; 403 } 404 405 406 bool 407 BPicture::_AssertOldLocalCopy() 408 { 409 // TODO: We don't support old data for now 410 411 return false; 412 } 413 414 415 bool 416 BPicture::_AssertServerCopy() 417 { 418 if (token != -1) 419 return true; 420 421 if (extent->Data() == NULL) 422 return false; 423 424 for (int32 i = 0; i < extent->CountPictures(); i++) 425 extent->PictureAt(i)->_AssertServerCopy(); 426 427 return _Upload() == B_OK; 428 } 429 430 431 status_t 432 BPicture::_Upload() 433 { 434 ASSERT((token == -1)); 435 ASSERT((extent->Data() != NULL)); 436 437 BPrivate::AppServerLink link; 438 439 link.StartMessage(AS_CREATE_PICTURE); 440 link.Attach<int32>(extent->CountPictures()); 441 442 for (int32 i = 0; i < extent->CountPictures(); i++) { 443 BPicture *picture = extent->PictureAt(i); 444 if (picture) 445 link.Attach<int32>(picture->token); 446 } 447 link.Attach<int32>(extent->Size()); 448 link.Attach(extent->Data(), extent->Size()); 449 450 status_t status = B_ERROR; 451 if (link.FlushWithReply(status) == B_OK 452 && status == B_OK) 453 link.Read<int32>(&token); 454 455 return status; 456 } 457 458 459 status_t 460 BPicture::_Download() 461 { 462 ASSERT((extent->Data() == NULL)); 463 ASSERT((token != -1)); 464 465 BPrivate::AppServerLink link; 466 467 link.StartMessage(AS_DOWNLOAD_PICTURE); 468 link.Attach<int32>(token); 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 *pic = new BPicture; 478 link.Read<int32>(&pic->token); 479 extent->AddPicture(pic); 480 } 481 482 int32 size; 483 link.Read<int32>(&size); 484 status = extent->SetSize(size); 485 if (status == B_OK) 486 link.Read(const_cast<void *>(extent->Data()), size); 487 } 488 489 return status; 490 } 491 492 493 const void * 494 BPicture::Data() const 495 { 496 if (extent->Data() == NULL) 497 const_cast<BPicture*>(this)->_AssertLocalCopy(); 498 499 return extent->Data(); 500 } 501 502 503 int32 504 BPicture::DataSize() const 505 { 506 if (extent->Data() == NULL) 507 const_cast<BPicture*>(this)->_AssertLocalCopy(); 508 509 return extent->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 usurped = lameDuck; 523 } 524 525 526 BPicture * 527 BPicture::StepDown() 528 { 529 BPicture *lameDuck = usurped; 530 usurped = 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_(const 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, const 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_::ImportData(BDataIO *stream) 585 { 586 if (stream == NULL) 587 return B_BAD_VALUE; 588 589 int32 size; 590 ssize_t bytesRead = stream->Read(&size, sizeof(size)); 591 if (bytesRead < B_OK) 592 return bytesRead; 593 if (bytesRead != (ssize_t)sizeof(size)) 594 return B_IO_ERROR; 595 596 status_t status = B_OK; 597 if (Size() != size) 598 status = SetSize(size); 599 600 if (status < B_OK) 601 return status; 602 603 bytesRead = stream->Read(fNewData, size); 604 if (bytesRead < B_OK) 605 return bytesRead; 606 if (bytesRead != (ssize_t)size) 607 return B_IO_ERROR; 608 609 return B_OK; 610 } 611 612 613 status_t 614 _BPictureExtent_::SetSize(const int32 &size) 615 { 616 if (size < 0) 617 return B_BAD_VALUE; 618 619 if (size == fNewSize) 620 return B_OK; 621 622 if (size == 0) { 623 free(fNewData); 624 fNewData = NULL; 625 } else { 626 void *data = realloc(fNewData, size); 627 if (data == NULL) 628 return B_NO_MEMORY; 629 fNewData = data; 630 } 631 632 fNewSize = size; 633 return B_OK; 634 } 635