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