* Copyright 2002-2011, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Travis Smith
* Michael Wilber
*/
#include <BitmapStream.h>
#include <new>
#include <string.h>
#include <Bitmap.h>
#include <Debug.h>
BBitmapStream::BBitmapStream(BBitmap* bitmap)
{
fBitmap = bitmap;
fDetached = false;
fPosition = 0;
fSize = 0;
fBigEndianHeader = new (std::nothrow) TranslatorBitmap;
if (fBigEndianHeader == NULL) {
fBitmap = NULL;
return;
}
if (fBitmap != NULL && fBitmap->InitCheck() == B_OK) {
fHeader.magic = B_TRANSLATOR_BITMAP;
fHeader.bounds = fBitmap->Bounds();
fHeader.rowBytes = fBitmap->BytesPerRow();
fHeader.colors = fBitmap->ColorSpace();
fHeader.dataSize = static_cast<uint32>
((fHeader.bounds.Height() + 1) * fHeader.rowBytes);
fSize = sizeof(TranslatorBitmap) + fHeader.dataSize;
if (B_HOST_IS_BENDIAN)
*fBigEndianHeader = fHeader;
else
SwapHeader(&fHeader, fBigEndianHeader);
} else
fBitmap = NULL;
}
BBitmapStream::~BBitmapStream()
{
if (!fDetached)
delete fBitmap;
delete fBigEndianHeader;
}
ssize_t
BBitmapStream::ReadAt(off_t pos, void* buffer, size_t size)
{
if (fBitmap == NULL)
return B_NO_INIT;
if (size == 0)
return B_OK;
if (pos >= (off_t)fSize || pos < 0 || buffer == NULL)
return B_BAD_VALUE;
ssize_t toRead;
void *source;
if (pos < (off_t)sizeof(TranslatorBitmap)) {
toRead = sizeof(TranslatorBitmap) - pos;
source = (reinterpret_cast<uint8 *>(fBigEndianHeader)) + pos;
} else {
toRead = fSize - pos;
source = (reinterpret_cast<uint8 *>(fBitmap->Bits())) + pos -
sizeof(TranslatorBitmap);
}
if (toRead > (ssize_t)size)
toRead = (ssize_t)size;
memcpy(buffer, source, toRead);
return toRead;
}
ssize_t
BBitmapStream::WriteAt(off_t pos, const void* data, size_t size)
{
if (size == 0)
return B_OK;
if (!data || pos < 0 || pos > (off_t)fSize)
return B_BAD_VALUE;
ssize_t written = 0;
while (size > 0) {
size_t toWrite;
void *dest;
if (pos < (off_t)sizeof(TranslatorBitmap)) {
toWrite = sizeof(TranslatorBitmap) - pos;
dest = (reinterpret_cast<uint8 *> (&fHeader)) + pos;
} else {
if (fBitmap == NULL || !fBitmap->IsValid())
return B_ERROR;
toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap);
dest = (reinterpret_cast<uint8 *> (fBitmap->Bits())) +
pos - sizeof(TranslatorBitmap);
}
if (toWrite > size)
toWrite = size;
if (!toWrite && size)
return B_BAD_VALUE;
memcpy(dest, data, toWrite);
pos += toWrite;
written += toWrite;
data = (reinterpret_cast<const uint8 *> (data)) + toWrite;
size -= toWrite;
if (pos > (off_t)fSize)
fSize = pos;
if (pos == sizeof(TranslatorBitmap)) {
*fBigEndianHeader = fHeader;
if (B_HOST_IS_LENDIAN)
SwapHeader(fBigEndianHeader, &fHeader);
if (fBitmap != NULL
&& (fBitmap->Bounds() != fHeader.bounds
|| fBitmap->ColorSpace() != fHeader.colors
|| (uint32)fBitmap->BytesPerRow() != fHeader.rowBytes)) {
if (!fDetached)
delete fBitmap;
fBitmap = NULL;
}
if (fBitmap == NULL) {
if (fHeader.bounds.left > 0.0 || fHeader.bounds.top > 0.0)
DEBUGGER("non-origin bounds!");
fBitmap = new (std::nothrow )BBitmap(fHeader.bounds,
0, fHeader.colors, fHeader.rowBytes);
if (fBitmap == NULL)
return B_ERROR;
if (!fBitmap->IsValid()) {
status_t error = fBitmap->InitCheck();
delete fBitmap;
fBitmap = NULL;
return error;
}
if ((uint32)fBitmap->BytesPerRow() != fHeader.rowBytes) {
fprintf(stderr, "BitmapStream BytesPerRow width %" B_PRId32 " does not match "
"value declared in header %" B_PRId32 "\n",
fBitmap->BytesPerRow(), fHeader.rowBytes);
return B_MISMATCHED_VALUES;
}
}
if (fBitmap != NULL)
fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength();
}
}
return written;
}
off_t
BBitmapStream::Seek(off_t position, uint32 seekMode)
{
if (seekMode == SEEK_CUR)
position += fPosition;
else if (seekMode == SEEK_END)
position += fSize;
if (position < 0 || position > (off_t)fSize)
return B_BAD_VALUE;
fPosition = position;
return fPosition;
}
off_t
BBitmapStream::Position() const
{
return fPosition;
}
off_t
BBitmapStream::Size() const
{
return fSize;
}
status_t
BBitmapStream::SetSize(off_t size)
{
if (size < 0)
return B_BAD_VALUE;
if (fBitmap && (size > (off_t)(fHeader.dataSize + sizeof(TranslatorBitmap))))
return B_BAD_VALUE;
if (fBitmap != NULL)
fSize = size;
return B_NO_ERROR;
}
status_t
BBitmapStream::DetachBitmap(BBitmap** _bitmap)
{
if (_bitmap == NULL)
return B_BAD_VALUE;
if (!fBitmap || fDetached)
return B_ERROR;
fDetached = true;
*_bitmap = fBitmap;
return B_OK;
}
void
BBitmapStream::SwapHeader(const TranslatorBitmap* source,
TranslatorBitmap* destination)
{
if (source == NULL || destination == NULL)
return;
*destination = *source;
swap_data(B_UINT32_TYPE, destination, sizeof(TranslatorBitmap),
B_SWAP_ALWAYS);
}
void BBitmapStream::_ReservedBitmapStream1() {}
void BBitmapStream::_ReservedBitmapStream2() {}