vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / Picture.cpp
blobbb2b3f51f23f1ce0142f65d0e900771c9e541ec1
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_(int32 size = 0);
66 ~_BPictureExtent_();
68 const void* Data() const { return fNewData; }
69 status_t ImportData(const void* data, int32 size);
71 status_t Flatten(BDataIO* stream);
72 status_t Unflatten(BDataIO* stream);
74 int32 Size() const { return fNewSize; }
75 status_t SetSize(int32 size);
77 bool AddPicture(BPicture* picture)
78 { return fPictures.AddItem(picture); }
79 void DeletePicture(int32 index)
80 { delete static_cast<BPicture*>
81 (fPictures.RemoveItem(index)); }
83 BList* Pictures() { return &fPictures; }
84 BPicture* PictureAt(int32 index)
85 { return static_cast<BPicture*>
86 (fPictures.ItemAt(index)); }
88 int32 CountPictures() const
89 { return fPictures.CountItems(); }
91 private:
92 void* fNewData;
93 int32 fNewSize;
95 BList fPictures;
96 // In R5 this is a BArray<BPicture*>
97 // which is completely inline.
101 struct picture_header {
102 int32 magic1; // version ?
103 int32 magic2; // endianess ?
107 BPicture::BPicture()
109 fToken(-1),
110 fExtent(NULL),
111 fUsurped(NULL)
113 _InitData();
117 BPicture::BPicture(const BPicture& otherPicture)
119 fToken(-1),
120 fExtent(NULL),
121 fUsurped(NULL)
123 _InitData();
125 if (otherPicture.fToken != -1) {
126 BPrivate::AppServerLink link;
127 link.StartMessage(AS_CLONE_PICTURE);
128 link.Attach<int32>(otherPicture.fToken);
130 status_t status = B_ERROR;
131 if (link.FlushWithReply(status) == B_OK && status == B_OK)
132 link.Read<int32>(&fToken);
134 if (status < B_OK)
135 return;
138 if (otherPicture.fExtent->Size() > 0) {
139 fExtent->ImportData(otherPicture.fExtent->Data(),
140 otherPicture.fExtent->Size());
142 for (int32 i = 0; i < otherPicture.fExtent->CountPictures(); i++) {
143 BPicture* picture
144 = new BPicture(*otherPicture.fExtent->PictureAt(i));
145 fExtent->AddPicture(picture);
151 BPicture::BPicture(BMessage* data)
153 fToken(-1),
154 fExtent(NULL),
155 fUsurped(NULL)
157 _InitData();
159 int32 version;
160 if (data->FindInt32("_ver", &version) != B_OK)
161 version = 0;
163 int8 endian;
164 if (data->FindInt8("_endian", &endian) != B_OK)
165 endian = 0;
167 const void* pictureData;
168 ssize_t size;
169 if (data->FindData("_data", B_RAW_TYPE, &pictureData, &size) != B_OK)
170 return;
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);
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);
186 // swap_data(fExtent->fNewData, fExtent->fNewSize);
188 if (fExtent->Size() > 0)
189 _AssertServerCopy();
192 // Do we just free the data now?
193 if (fExtent->Size() > 0)
194 fExtent->SetSize(0);
196 // What with the sub pictures?
197 for (i = fExtent->CountPictures() - 1; i >= 0; i--)
198 fExtent->DeletePicture(i);
202 BPicture::BPicture(const void* data, int32 size)
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");
210 void
211 BPicture::_InitData()
213 fToken = -1;
214 fUsurped = NULL;
216 fExtent = new (std::nothrow) _BPictureExtent_;
218 BAutolock _(sPictureListLock);
219 sPictureList.AddItem(this);
223 BPicture::~BPicture()
225 BAutolock _(sPictureListLock);
226 sPictureList.RemoveItem(this, false);
227 _DisposeData();
231 void
232 BPicture::_DisposeData()
234 if (fToken != -1) {
235 BPrivate::AppServerLink link;
237 link.StartMessage(AS_DELETE_PICTURE);
238 link.Attach<int32>(fToken);
239 link.Flush();
240 SetToken(-1);
243 delete fExtent;
244 fExtent = NULL;
248 BArchivable*
249 BPicture::Instantiate(BMessage* data)
251 if (validate_instantiation(data, "BPicture"))
252 return new BPicture(data);
254 return NULL;
258 status_t
259 BPicture::Archive(BMessage* data, bool deep) const
261 if (!const_cast<BPicture*>(this)->_AssertLocalCopy())
262 return B_ERROR;
264 status_t err = BArchivable::Archive(data, deep);
265 if (err != B_OK)
266 return err;
268 err = data->AddInt32("_ver", 1);
269 if (err != B_OK)
270 return err;
272 err = data->AddInt8("_endian", B_HOST_IS_BENDIAN);
273 if (err != B_OK)
274 return err;
276 err = data->AddData("_data", B_RAW_TYPE, fExtent->Data(), fExtent->Size());
277 if (err != B_OK)
278 return err;
280 for (int32 i = 0; i < fExtent->CountPictures(); i++) {
281 BMessage pictureMessage;
283 err = fExtent->PictureAt(i)->Archive(&pictureMessage, deep);
284 if (err != B_OK)
285 break;
287 err = data->AddMessage("piclib", &pictureMessage);
288 if (err != B_OK)
289 break;
292 return err;
296 status_t
297 BPicture::Perform(perform_code code, void* arg)
299 return BArchivable::Perform(code, arg);
303 status_t
304 BPicture::Play(void** callBackTable, int32 tableEntries, void* user)
306 if (!_AssertLocalCopy())
307 return B_ERROR;
309 BPrivate::PicturePlayer player(fExtent->Data(), fExtent->Size(),
310 fExtent->Pictures());
312 return player.Play(callBackTable, tableEntries, user);
316 status_t
317 BPicture::Flatten(BDataIO* stream)
319 // TODO: what about endianess?
321 if (!_AssertLocalCopy())
322 return B_ERROR;
324 const picture_header header = { 2, 0 };
325 ssize_t bytesWritten = stream->Write(&header, sizeof(header));
326 if (bytesWritten < B_OK)
327 return bytesWritten;
329 if (bytesWritten != (ssize_t)sizeof(header))
330 return B_IO_ERROR;
332 return fExtent->Flatten(stream);
336 status_t
337 BPicture::Unflatten(BDataIO* stream)
339 // TODO: clear current picture data?
341 picture_header header;
342 ssize_t bytesRead = stream->Read(&header, sizeof(header));
343 if (bytesRead < B_OK)
344 return bytesRead;
346 if (bytesRead != (ssize_t)sizeof(header)
347 || header.magic1 != 2 || header.magic2 != 0)
348 return B_BAD_TYPE;
350 status_t status = fExtent->Unflatten(stream);
351 if (status < B_OK)
352 return status;
354 // swap_data(fExtent->fNewData, fExtent->fNewSize);
356 if (!_AssertServerCopy())
357 return B_ERROR;
359 // Data is now kept server side, remove the local copy
360 if (fExtent->Data() != NULL)
361 fExtent->SetSize(0);
363 return status;
367 void
368 BPicture::_ImportOldData(const void* data, int32 size)
370 // TODO: We don't support old data for now
374 void
375 BPicture::SetToken(int32 token)
377 fToken = token;
381 int32
382 BPicture::Token() const
384 return fToken;
388 bool
389 BPicture::_AssertLocalCopy()
391 if (fExtent->Data() != NULL)
392 return true;
394 if (fToken == -1)
395 return false;
397 return _Download() == B_OK;
401 bool
402 BPicture::_AssertOldLocalCopy()
404 // TODO: We don't support old data for now
406 return false;
410 bool
411 BPicture::_AssertServerCopy()
413 if (fToken != -1)
414 return true;
416 if (fExtent->Data() == NULL)
417 return false;
419 for (int32 i = 0; i < fExtent->CountPictures(); i++) {
420 if (!fExtent->PictureAt(i)->_AssertServerCopy())
421 return false;
424 return _Upload() == B_OK;
428 status_t
429 BPicture::_Upload()
431 if (fExtent == NULL || fExtent->Data() == NULL)
432 return B_BAD_VALUE;
434 BPrivate::AppServerLink link;
436 link.StartMessage(AS_CREATE_PICTURE);
437 link.Attach<int32>(fExtent->CountPictures());
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);
446 link.Attach<int32>(fExtent->Size());
447 link.Attach(fExtent->Data(), fExtent->Size());
449 status_t status = B_ERROR;
450 if (link.FlushWithReply(status) == B_OK
451 && status == B_OK) {
452 link.Read<int32>(&fToken);
455 return status;
459 status_t
460 BPicture::_Download()
462 ASSERT(fExtent->Data() == NULL);
463 ASSERT(fToken != -1);
465 BPrivate::AppServerLink link;
467 link.StartMessage(AS_DOWNLOAD_PICTURE);
468 link.Attach<int32>(fToken);
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);
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);
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);
489 return status;
493 const void*
494 BPicture::Data() const
496 if (fExtent->Data() == NULL)
497 const_cast<BPicture*>(this)->_AssertLocalCopy();
499 return fExtent->Data();
503 int32
504 BPicture::DataSize() const
506 if (fExtent->Data() == NULL)
507 const_cast<BPicture*>(this)->_AssertLocalCopy();
509 return fExtent->Size();
513 void
514 BPicture::Usurp(BPicture* lameDuck)
516 _DisposeData();
518 // Reinitializes the BPicture
519 _InitData();
521 // Do the Usurping
522 fUsurped = lameDuck;
526 BPicture*
527 BPicture::StepDown()
529 BPicture* lameDuck = fUsurped;
530 fUsurped = NULL;
532 return lameDuck;
536 void BPicture::_ReservedPicture1() {}
537 void BPicture::_ReservedPicture2() {}
538 void BPicture::_ReservedPicture3() {}
541 BPicture&
542 BPicture::operator=(const BPicture&)
544 return* this;
548 // _BPictureExtent_
549 _BPictureExtent_::_BPictureExtent_(int32 size)
551 fNewData(NULL),
552 fNewSize(0)
554 SetSize(size);
558 _BPictureExtent_::~_BPictureExtent_()
560 free(fNewData);
561 for (int32 i = 0; i < fPictures.CountItems(); i++)
562 delete static_cast<BPicture*>(fPictures.ItemAtFast(i));
566 status_t
567 _BPictureExtent_::ImportData(const void* data, int32 size)
569 if (data == NULL)
570 return B_BAD_VALUE;
572 status_t status = B_OK;
573 if (Size() != size)
574 status = SetSize(size);
576 if (status == B_OK)
577 memcpy(fNewData, data, size);
579 return status;
583 status_t
584 _BPictureExtent_::Unflatten(BDataIO* stream)
586 if (stream == NULL)
587 return B_BAD_VALUE;
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;
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;
604 AddPicture(picture);
607 int32 size;
608 bytesRead = stream->Read(&size, sizeof(size));
609 if (bytesRead < B_OK)
610 return bytesRead;
612 if (bytesRead != (ssize_t)sizeof(size))
613 return B_IO_ERROR;
615 status_t status = B_OK;
616 if (Size() != size)
617 status = SetSize(size);
619 if (status < B_OK)
620 return status;
622 bytesRead = stream->Read(fNewData, size);
623 if (bytesRead < B_OK)
624 return bytesRead;
626 if (bytesRead != (ssize_t)size)
627 return B_IO_ERROR;
629 return B_OK;
633 status_t
634 _BPictureExtent_::Flatten(BDataIO* stream)
636 int32 count = fPictures.CountItems();
637 ssize_t bytesWritten = stream->Write(&count, sizeof(count));
638 if (bytesWritten < B_OK)
639 return bytesWritten;
641 if (bytesWritten != (ssize_t)sizeof(count))
642 return B_IO_ERROR;
644 for (int32 i = 0; i < count; i++) {
645 status_t status = PictureAt(i)->Flatten(stream);
646 if (status < B_OK)
647 return status;
650 bytesWritten = stream->Write(&fNewSize, sizeof(fNewSize));
651 if (bytesWritten < B_OK)
652 return bytesWritten;
654 if (bytesWritten != (ssize_t)sizeof(fNewSize))
655 return B_IO_ERROR;
657 bytesWritten = stream->Write(fNewData, fNewSize);
658 if (bytesWritten < B_OK)
659 return bytesWritten;
661 if (bytesWritten != fNewSize)
662 return B_IO_ERROR;
664 return B_OK;
668 status_t
669 _BPictureExtent_::SetSize(int32 size)
671 if (size < 0)
672 return B_BAD_VALUE;
674 if (size == fNewSize)
675 return B_OK;
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;
685 fNewData = data;
688 fNewSize = size;
689 return B_OK;