1 /* 2 * Copyright 2002-2011, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Travis Smith 7 * Michael Wilber 8 */ 9 10 11 #include <BitmapStream.h> 12 13 #include <new> 14 15 #include <string.h> 16 17 #include <Bitmap.h> 18 #include <Debug.h> 19 20 21 /*! Initializes this object to either use the BBitmap passed to 22 it as the object to read/write to or to create a BBitmap 23 when data is written to this object. 24 25 \param bitmap the bitmap used to read from/write to, if it is NULL, a 26 bitmap is created when this object is written to. 27 */ 28 BBitmapStream::BBitmapStream(BBitmap* bitmap) 29 { 30 fBitmap = bitmap; 31 fDetached = false; 32 fPosition = 0; 33 fSize = 0; 34 fBigEndianHeader = new (std::nothrow) TranslatorBitmap; 35 if (fBigEndianHeader == NULL) { 36 fBitmap = NULL; 37 return; 38 } 39 40 // Extract header information if bitmap is available 41 if (fBitmap != NULL && fBitmap->InitCheck() == B_OK) { 42 fHeader.magic = B_TRANSLATOR_BITMAP; 43 fHeader.bounds = fBitmap->Bounds(); 44 fHeader.rowBytes = fBitmap->BytesPerRow(); 45 fHeader.colors = fBitmap->ColorSpace(); 46 fHeader.dataSize = static_cast<uint32> 47 ((fHeader.bounds.Height() + 1) * fHeader.rowBytes); 48 fSize = sizeof(TranslatorBitmap) + fHeader.dataSize; 49 50 if (B_HOST_IS_BENDIAN) 51 memcpy(fBigEndianHeader, &fHeader, sizeof(TranslatorBitmap)); 52 else 53 SwapHeader(&fHeader, fBigEndianHeader); 54 } else 55 fBitmap = NULL; 56 } 57 58 59 BBitmapStream::~BBitmapStream() 60 { 61 if (!fDetached) 62 delete fBitmap; 63 64 delete fBigEndianHeader; 65 } 66 67 68 /*! Reads data from the stream at a specific position and for a 69 specific amount. The first sizeof(TranslatorBitmap) bytes 70 are the bitmap header. The header is always written out 71 and read in as Big Endian byte order. 72 73 \param pos, the position in the stream to read from buffer, where the data 74 will be read into size, the amount of data to read 75 \return B_ERROR if there is no bitmap stored by the stream, B_BAD_VALUE if 76 buffer is NULL or pos is invalid or the amount read if the result >= 0 77 */ 78 ssize_t 79 BBitmapStream::ReadAt(off_t pos, void* buffer, size_t size) 80 { 81 if (fBitmap == NULL) 82 return B_NO_INIT; 83 if (size == 0) 84 return B_OK; 85 if (pos >= (off_t)fSize || pos < 0 || buffer == NULL) 86 return B_BAD_VALUE; 87 88 ssize_t toRead; 89 void *source; 90 91 if (pos < (off_t)sizeof(TranslatorBitmap)) { 92 toRead = sizeof(TranslatorBitmap) - pos; 93 source = (reinterpret_cast<uint8 *>(fBigEndianHeader)) + pos; 94 } else { 95 toRead = fSize - pos; 96 source = (reinterpret_cast<uint8 *>(fBitmap->Bits())) + pos - 97 sizeof(TranslatorBitmap); 98 } 99 if (toRead > (ssize_t)size) 100 toRead = (ssize_t)size; 101 102 memcpy(buffer, source, toRead); 103 return toRead; 104 } 105 106 107 /*! Writes data to the bitmap from data, starting at position pos 108 of size, size. The first sizeof(TranslatorBitmap) bytes 109 of data must be the TranslatorBitmap header in the Big 110 Endian byte order, otherwise, the data will fail to be 111 successfully written. 112 113 \param pos, the position in the stream to write to data, the data to write 114 to the stream size, the size of the data to write to the stream 115 \return B_BAD_VALUE if size is bad or data is NULL or pos is invalid, 116 B_MISMATCHED_VALUES if the bitmap header is bad, 117 B_ERROR if error allocating memory or setting up big endian header, 118 or the amount written if the result is >= 0 119 */ 120 ssize_t 121 BBitmapStream::WriteAt(off_t pos, const void* data, size_t size) 122 { 123 if (size == 0) 124 return B_OK; 125 if (!data || pos < 0 || pos > (off_t)fSize) 126 return B_BAD_VALUE; 127 128 ssize_t written = 0; 129 while (size > 0) { 130 size_t toWrite; 131 void *dest; 132 // We depend on writing the header separately in detecting 133 // changes to it 134 if (pos < (off_t)sizeof(TranslatorBitmap)) { 135 toWrite = sizeof(TranslatorBitmap) - pos; 136 dest = (reinterpret_cast<uint8 *> (&fHeader)) + pos; 137 } else { 138 if (fBitmap == NULL || !fBitmap->IsValid()) 139 return B_ERROR; 140 141 toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap); 142 dest = (reinterpret_cast<uint8 *> (fBitmap->Bits())) + 143 pos - sizeof(TranslatorBitmap); 144 } 145 if (toWrite > size) 146 toWrite = size; 147 if (!toWrite && size) 148 // i.e. we've been told to write too much 149 return B_BAD_VALUE; 150 151 memcpy(dest, data, toWrite); 152 pos += toWrite; 153 written += toWrite; 154 data = (reinterpret_cast<const uint8 *> (data)) + toWrite; 155 size -= toWrite; 156 if (pos > (off_t)fSize) 157 fSize = pos; 158 // If we change the header, the rest needs to be reset 159 if (pos == sizeof(TranslatorBitmap)) { 160 // Setup both host and Big Endian byte order bitmap headers 161 memcpy(fBigEndianHeader, &fHeader, sizeof(TranslatorBitmap)); 162 if (B_HOST_IS_LENDIAN) 163 SwapHeader(fBigEndianHeader, &fHeader); 164 165 if (fBitmap != NULL 166 && (fBitmap->Bounds() != fHeader.bounds 167 || fBitmap->ColorSpace() != fHeader.colors 168 || (uint32)fBitmap->BytesPerRow() != fHeader.rowBytes)) { 169 if (!fDetached) 170 // if someone detached, we don't delete 171 delete fBitmap; 172 fBitmap = NULL; 173 } 174 if (fBitmap == NULL) { 175 if (fHeader.bounds.left > 0.0 || fHeader.bounds.top > 0.0) 176 DEBUGGER("non-origin bounds!"); 177 fBitmap = new (std::nothrow )BBitmap(fHeader.bounds, 178 fHeader.colors); 179 if (fBitmap == NULL) 180 return B_ERROR; 181 if (!fBitmap->IsValid()) { 182 status_t error = fBitmap->InitCheck(); 183 delete fBitmap; 184 fBitmap = NULL; 185 return error; 186 } 187 if ((uint32)fBitmap->BytesPerRow() != fHeader.rowBytes) { 188 fprintf(stderr, "BitmapStream %" B_PRId32 " %" B_PRId32 "\n", 189 fBitmap->BytesPerRow(), fHeader.rowBytes); 190 return B_MISMATCHED_VALUES; 191 } 192 } 193 if (fBitmap != NULL) 194 fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength(); 195 } 196 } 197 return written; 198 } 199 200 201 /*! Changes the current stream position. 202 203 \param position the position offset 204 \param seekMode decides how the position offset is used: 205 SEEK_CUR, position is added to current stream position 206 SEEK_END, position is added to the end stream position 207 SEEK_SET, the stream position is set to position 208 \return B_BAD_VALUE if the position is bad or the new position value if the 209 result >= 0 210 */ 211 off_t 212 BBitmapStream::Seek(off_t position, uint32 seekMode) 213 { 214 // When whence == SEEK_SET, it just falls through to 215 // fPosition = position 216 if (seekMode == SEEK_CUR) 217 position += fPosition; 218 else if (seekMode == SEEK_END) 219 position += fSize; 220 221 if (position < 0 || position > (off_t)fSize) 222 return B_BAD_VALUE; 223 224 fPosition = position; 225 return fPosition; 226 } 227 228 229 /*! Returns the current stream position 230 */ 231 off_t 232 BBitmapStream::Position() const 233 { 234 return fPosition; 235 } 236 237 238 239 /*! Returns the curren stream size 240 */ 241 off_t 242 BBitmapStream::Size() const 243 { 244 return fSize; 245 } 246 247 248 /*! Sets the size of the data, but I'm not sure if this function has any real 249 purpose. 250 251 \param size the size to set the stream size to. 252 \return B_BAD_VALUE, if size is a bad value, B_NO_ERROR, if size is a 253 valid value 254 */ 255 status_t 256 BBitmapStream::SetSize(off_t size) 257 { 258 if (size < 0) 259 return B_BAD_VALUE; 260 if (fBitmap && (size > (off_t)(fHeader.dataSize + sizeof(TranslatorBitmap)))) 261 return B_BAD_VALUE; 262 // Problem: 263 // What if someone calls SetSize() before writing the header, 264 // so we don't know what bitmap to create? 265 // Solution: 266 // We assume people will write the header before any data, 267 // so SetSize() is really not going to do anything. 268 if (fBitmap != NULL) 269 fSize = size; 270 271 return B_NO_ERROR; 272 } 273 274 275 /*! Returns the internal bitmap through outBitmap so the user 276 can do whatever they want to it. It means that when the 277 BBitmapStream is deleted, the bitmap is not deleted. After 278 the bitmap has been detached, it is still used by the stream, 279 but it is never deleted by the stream. 280 281 \param _bitmap where the bitmap is detached to 282 \return B_BAD_VALUE, if outBitmap is NULL, B_ERROR, if the bitmap is NULL or 283 has already been detached, B_OK, if the bitmap was successfully detached 284 */ 285 status_t 286 BBitmapStream::DetachBitmap(BBitmap** _bitmap) 287 { 288 if (_bitmap == NULL) 289 return B_BAD_VALUE; 290 if (!fBitmap || fDetached) 291 return B_ERROR; 292 293 fDetached = true; 294 *_bitmap = fBitmap; 295 296 return B_OK; 297 } 298 299 300 /*! Swaps the byte order of source, no matter what the 301 byte order, and copies the result to destination 302 303 \param source data to be swapped 304 \param destination where the swapped data will be copied to 305 */ 306 void 307 BBitmapStream::SwapHeader(const TranslatorBitmap* source, 308 TranslatorBitmap* destination) 309 { 310 if (source == NULL || destination == NULL) 311 return; 312 313 memcpy(destination, source, sizeof(TranslatorBitmap)); 314 swap_data(B_UINT32_TYPE, destination, sizeof(TranslatorBitmap), 315 B_SWAP_ALWAYS); 316 } 317 318 319 void BBitmapStream::_ReservedBitmapStream1() {} 320 void BBitmapStream::_ReservedBitmapStream2() {} 321