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