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