tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / Picture.cpp
blob064a51ab15c340ec5ae6b34ecd91b6c74e80f42f
1 /*
2 * Copyright 2001-2014 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marc Flerackers, mflerackers@androme.be
7 */
10 // Records a series of drawing instructions that can be "replayed" later.
13 #include <Picture.h>
15 #include <new>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
20 //#define DEBUG 1
21 #include <ByteOrder.h>
22 #include <Debug.h>
23 #include <List.h>
24 #include <Message.h>
26 #include <AppServerLink.h>
27 #include <Autolock.h>
28 #include <ObjectList.h>
29 #include <PicturePlayer.h>
30 #include <ServerProtocol.h>
32 #include "PicturePrivate.h"
35 static BObjectList<BPicture> sPictureList;
36 static BLocker sPictureListLock;
39 void
40 reconnect_pictures_to_app_server()
42 BAutolock _(sPictureListLock);
43 for (int32 i = 0; i < sPictureList.CountItems(); i++) {
44 BPicture::Private picture(sPictureList.ItemAt(i));
45 picture.ReconnectToAppServer();
50 BPicture::Private::Private(BPicture* picture)
52 fPicture(picture)
57 void
58 BPicture::Private::ReconnectToAppServer()
60 fPicture->_Upload();
64 struct _BPictureExtent_ {
65 _BPictureExtent_(const int32& size = 0);
66 ~_BPictureExtent_();
68 const void* Data() const { return fNewData; }
69 status_t ImportData(const void* data,
70 const int32& size);
72 status_t Flatten(BDataIO* stream);
73 status_t Unflatten(BDataIO* stream);
75 int32 Size() const { return fNewSize; }
76 status_t SetSize(const int32& size);
78 bool AddPicture(BPicture* picture)
79 { return fPictures.AddItem(picture); }
80 void DeletePicture(const int32& index)
81 { delete static_cast<BPicture*>
82 (fPictures.RemoveItem(index)); }
84 BList* Pictures() { return &fPictures; }
85 BPicture* PictureAt(const int32& index)
86 { return static_cast<BPicture*>
87 (fPictures.ItemAt(index)); }
89 int32 CountPictures() const
90 { return fPictures.CountItems(); }
92 private:
93 void* fNewData;
94 int32 fNewSize;
96 BList fPictures;
97 // In R5 this is a BArray<BPicture*>
98 // which is completely inline.
102 struct picture_header {
103 int32 magic1; // version ?
104 int32 magic2; // endianess ?
108 BPicture::BPicture()
110 fToken(-1),
111 fExtent(NULL),
112 fUsurped(NULL)
114 _InitData();
118 BPicture::BPicture(const BPicture& otherPicture)
120 fToken(-1),
121 fExtent(NULL),
122 fUsurped(NULL)
124 _InitData();
126 if (otherPicture.fToken != -1) {
127 BPrivate::AppServerLink link;
128 link.StartMessage(AS_CLONE_PICTURE);
129 link.Attach<int32>(otherPicture.fToken);
131 status_t status = B_ERROR;
132 if (link.FlushWithReply(status) == B_OK && status == B_OK)
133 link.Read<int32>(&fToken);
135 if (status < B_OK)
136 return;
139 if (otherPicture.fExtent->Size() > 0) {
140 fExtent->ImportData(otherPicture.fExtent->Data(),
141 otherPicture.fExtent->Size());
143 for (int32 i = 0; i < otherPicture.fExtent->CountPictures(); i++) {
144 BPicture* picture
145 = new BPicture(*otherPicture.fExtent->PictureAt(i));
146 fExtent->AddPicture(picture);
152 BPicture::BPicture(BMessage* data)
154 fToken(-1),
155 fExtent(NULL),
156 fUsurped(NULL)
158 _InitData();
160 int32 version;
161 if (data->FindInt32("_ver", &version) != B_OK)
162 version = 0;
164 int8 endian;
165 if (data->FindInt8("_endian", &endian) != B_OK)
166 endian = 0;
168 const void* pictureData;
169 int32 size;
170 if (data->FindData("_data", B_RAW_TYPE, &pictureData, (ssize_t*)&size)
171 != B_OK) {
172 return;
175 // Load sub pictures
176 BMessage pictureMessage;
177 int32 i = 0;
178 while (data->FindMessage("piclib", i++, &pictureMessage) == B_OK) {
179 BPicture* picture = new BPicture(&pictureMessage);
180 fExtent->AddPicture(picture);
183 if (version == 0) {
184 // TODO: For now. We'll see if it's worth to support old style data
185 debugger("old style BPicture data is not supported");
186 } else if (version == 1) {
187 fExtent->ImportData(data, size);
189 // swap_data(fExtent->fNewData, fExtent->fNewSize);
191 if (fExtent->Size() > 0)
192 _AssertServerCopy();
195 // Do we just free the data now?
196 if (fExtent->Size() > 0)
197 fExtent->SetSize(0);
199 // What with the sub pictures?
200 for (i = fExtent->CountPictures() - 1; i >= 0; i--)
201 fExtent->DeletePicture(i);
205 BPicture::BPicture(const void* data, int32 size)
207 _InitData();
208 // TODO: For now. We'll see if it's worth to support old style data
209 debugger("old style BPicture data is not supported");
213 void
214 BPicture::_InitData()
216 fToken = -1;
217 fUsurped = NULL;
219 fExtent = new (std::nothrow) _BPictureExtent_;
221 BAutolock _(sPictureListLock);
222 sPictureList.AddItem(this);
226 BPicture::~BPicture()
228 BAutolock _(sPictureListLock);
229 sPictureList.RemoveItem(this, false);
230 _DisposeData();
234 void
235 BPicture::_DisposeData()
237 if (fToken != -1) {
238 BPrivate::AppServerLink link;
240 link.StartMessage(AS_DELETE_PICTURE);
241 link.Attach<int32>(fToken);
242 link.Flush();
243 SetToken(-1);
246 delete fExtent;
247 fExtent = NULL;
251 BArchivable*
252 BPicture::Instantiate(BMessage* data)
254 if (validate_instantiation(data, "BPicture"))
255 return new BPicture(data);
257 return NULL;
261 status_t
262 BPicture::Archive(BMessage* data, bool deep) const
264 if (!const_cast<BPicture*>(this)->_AssertLocalCopy())
265 return B_ERROR;
267 status_t err = BArchivable::Archive(data, deep);
268 if (err != B_OK)
269 return err;
271 err = data->AddInt32("_ver", 1);
272 if (err != B_OK)
273 return err;
275 err = data->AddInt8("_endian", B_HOST_IS_BENDIAN);
276 if (err != B_OK)
277 return err;
279 err = data->AddData("_data", B_RAW_TYPE, fExtent->Data(), fExtent->Size());
280 if (err != B_OK)
281 return err;
283 for (int32 i = 0; i < fExtent->CountPictures(); i++) {
284 BMessage pictureMessage;
286 err = fExtent->PictureAt(i)->Archive(&pictureMessage, deep);
287 if (err != B_OK)
288 break;
290 err = data->AddMessage("piclib", &pictureMessage);
291 if (err != B_OK)
292 break;
295 return err;
299 status_t
300 BPicture::Perform(perform_code code, void* arg)
302 return BArchivable::Perform(code, arg);
306 status_t
307 BPicture::Play(void** callBackTable, int32 tableEntries, void* user)
309 if (!_AssertLocalCopy())
310 return B_ERROR;
312 BPrivate::PicturePlayer player(fExtent->Data(), fExtent->Size(),
313 fExtent->Pictures());
315 return player.Play(callBackTable, tableEntries, user);
319 status_t
320 BPicture::Flatten(BDataIO* stream)
322 // TODO: what about endianess?
324 if (!_AssertLocalCopy())
325 return B_ERROR;
327 const picture_header header = { 2, 0 };
328 ssize_t bytesWritten = stream->Write(&header, sizeof(header));
329 if (bytesWritten < B_OK)
330 return bytesWritten;
332 if (bytesWritten != (ssize_t)sizeof(header))
333 return B_IO_ERROR;
335 return fExtent->Flatten(stream);
339 status_t
340 BPicture::Unflatten(BDataIO* stream)
342 // TODO: clear current picture data?
344 picture_header header;
345 ssize_t bytesRead = stream->Read(&header, sizeof(header));
346 if (bytesRead < B_OK)
347 return bytesRead;
349 if (bytesRead != (ssize_t)sizeof(header)
350 || header.magic1 != 2 || header.magic2 != 0)
351 return B_BAD_TYPE;
353 status_t status = fExtent->Unflatten(stream);
354 if (status < B_OK)
355 return status;
357 // swap_data(fExtent->fNewData, fExtent->fNewSize);
359 if (!_AssertServerCopy())
360 return B_ERROR;
362 // Data is now kept server side, remove the local copy
363 if (fExtent->Data() != NULL)
364 fExtent->SetSize(0);
366 return status;
370 void
371 BPicture::_ImportOldData(const void* data, int32 size)
373 // TODO: We don't support old data for now
377 void
378 BPicture::SetToken(int32 token)
380 fToken = token;
384 int32
385 BPicture::Token() const
387 return fToken;
391 bool
392 BPicture::_AssertLocalCopy()
394 if (fExtent->Data() != NULL)
395 return true;
397 if (fToken == -1)
398 return false;
400 return _Download() == B_OK;
404 bool
405 BPicture::_AssertOldLocalCopy()
407 // TODO: We don't support old data for now
409 return false;
413 bool
414 BPicture::_AssertServerCopy()
416 if (fToken != -1)
417 return true;
419 if (fExtent->Data() == NULL)
420 return false;
422 for (int32 i = 0; i < fExtent->CountPictures(); i++) {
423 if (!fExtent->PictureAt(i)->_AssertServerCopy())
424 return false;
427 return _Upload() == B_OK;
431 status_t
432 BPicture::_Upload()
434 if (fExtent == NULL || fExtent->Data() == NULL)
435 return B_BAD_VALUE;
437 BPrivate::AppServerLink link;
439 link.StartMessage(AS_CREATE_PICTURE);
440 link.Attach<int32>(fExtent->CountPictures());
442 for (int32 i = 0; i < fExtent->CountPictures(); i++) {
443 BPicture* picture = fExtent->PictureAt(i);
444 if (picture != NULL)
445 link.Attach<int32>(picture->fToken);
446 else
447 link.Attach<int32>(-1);
449 link.Attach<int32>(fExtent->Size());
450 link.Attach(fExtent->Data(), fExtent->Size());
452 status_t status = B_ERROR;
453 if (link.FlushWithReply(status) == B_OK
454 && status == B_OK) {
455 link.Read<int32>(&fToken);
458 return status;
462 status_t
463 BPicture::_Download()
465 ASSERT(fExtent->Data() == NULL);
466 ASSERT(fToken != -1);
468 BPrivate::AppServerLink link;
470 link.StartMessage(AS_DOWNLOAD_PICTURE);
471 link.Attach<int32>(fToken);
473 status_t status = B_ERROR;
474 if (link.FlushWithReply(status) == B_OK && status == B_OK) {
475 int32 count = 0;
476 link.Read<int32>(&count);
478 // Read sub picture tokens
479 for (int32 i = 0; i < count; i++) {
480 BPicture* picture = new BPicture;
481 link.Read<int32>(&picture->fToken);
482 fExtent->AddPicture(picture);
485 int32 size;
486 link.Read<int32>(&size);
487 status = fExtent->SetSize(size);
488 if (status == B_OK)
489 link.Read(const_cast<void*>(fExtent->Data()), size);
492 return status;
496 const void*
497 BPicture::Data() const
499 if (fExtent->Data() == NULL)
500 const_cast<BPicture*>(this)->_AssertLocalCopy();
502 return fExtent->Data();
506 int32
507 BPicture::DataSize() const
509 if (fExtent->Data() == NULL)
510 const_cast<BPicture*>(this)->_AssertLocalCopy();
512 return fExtent->Size();
516 void
517 BPicture::Usurp(BPicture* lameDuck)
519 _DisposeData();
521 // Reinitializes the BPicture
522 _InitData();
524 // Do the Usurping
525 fUsurped = lameDuck;
529 BPicture*
530 BPicture::StepDown()
532 BPicture* lameDuck = fUsurped;
533 fUsurped = NULL;
535 return lameDuck;
539 void BPicture::_ReservedPicture1() {}
540 void BPicture::_ReservedPicture2() {}
541 void BPicture::_ReservedPicture3() {}
544 BPicture&
545 BPicture::operator=(const BPicture&)
547 return* this;
551 // _BPictureExtent_
552 _BPictureExtent_::_BPictureExtent_(const int32& size)
554 fNewData(NULL),
555 fNewSize(0)
557 SetSize(size);
561 _BPictureExtent_::~_BPictureExtent_()
563 free(fNewData);
564 for (int32 i = 0; i < fPictures.CountItems(); i++)
565 delete static_cast<BPicture*>(fPictures.ItemAtFast(i));
569 status_t
570 _BPictureExtent_::ImportData(const void* data, const int32& size)
572 if (data == NULL)
573 return B_BAD_VALUE;
575 status_t status = B_OK;
576 if (Size() != size)
577 status = SetSize(size);
579 if (status == B_OK)
580 memcpy(fNewData, data, size);
582 return status;
586 status_t
587 _BPictureExtent_::Unflatten(BDataIO* stream)
589 if (stream == NULL)
590 return B_BAD_VALUE;
592 int32 count = 0;
593 ssize_t bytesRead = stream->Read(&count, sizeof(count));
594 if (bytesRead < B_OK)
595 return bytesRead;
596 if (bytesRead != (ssize_t)sizeof(count))
597 return B_BAD_DATA;
599 for (int32 i = 0; i < count; i++) {
600 BPicture* picture = new BPicture;
601 status_t status = picture->Unflatten(stream);
602 if (status < B_OK) {
603 delete picture;
604 return status;
607 AddPicture(picture);
610 int32 size;
611 bytesRead = stream->Read(&size, sizeof(size));
612 if (bytesRead < B_OK)
613 return bytesRead;
615 if (bytesRead != (ssize_t)sizeof(size))
616 return B_IO_ERROR;
618 status_t status = B_OK;
619 if (Size() != size)
620 status = SetSize(size);
622 if (status < B_OK)
623 return status;
625 bytesRead = stream->Read(fNewData, size);
626 if (bytesRead < B_OK)
627 return bytesRead;
629 if (bytesRead != (ssize_t)size)
630 return B_IO_ERROR;
632 return B_OK;
636 status_t
637 _BPictureExtent_::Flatten(BDataIO* stream)
639 int32 count = fPictures.CountItems();
640 ssize_t bytesWritten = stream->Write(&count, sizeof(count));
641 if (bytesWritten < B_OK)
642 return bytesWritten;
644 if (bytesWritten != (ssize_t)sizeof(count))
645 return B_IO_ERROR;
647 for (int32 i = 0; i < count; i++) {
648 status_t status = PictureAt(i)->Flatten(stream);
649 if (status < B_OK)
650 return status;
653 bytesWritten = stream->Write(&fNewSize, sizeof(fNewSize));
654 if (bytesWritten < B_OK)
655 return bytesWritten;
657 if (bytesWritten != (ssize_t)sizeof(fNewSize))
658 return B_IO_ERROR;
660 bytesWritten = stream->Write(fNewData, fNewSize);
661 if (bytesWritten < B_OK)
662 return bytesWritten;
664 if (bytesWritten != fNewSize)
665 return B_IO_ERROR;
667 return B_OK;
671 status_t
672 _BPictureExtent_::SetSize(const int32& size)
674 if (size < 0)
675 return B_BAD_VALUE;
677 if (size == fNewSize)
678 return B_OK;
680 if (size == 0) {
681 free(fNewData);
682 fNewData = NULL;
683 } else {
684 void* data = realloc(fNewData, size);
685 if (data == NULL)
686 return B_NO_MEMORY;
688 fNewData = data;
691 fNewSize = size;
692 return B_OK;