1 /*****************************************************************************/ 2 // File: BitmapStream.cpp 3 // Class: BBitmapStream 4 // Reimplemented by: Travis Smith, Michael Wilber, Translation Kit Team 5 // Reimplementation: 2002-04 6 // 7 // Description: BPositionIO based object to read/write bitmap format to/from 8 // a BBitmap object. 9 // 10 // The BTranslationUtils class uses this object and makes it 11 // easy for users to load bitmaps. 12 // 13 // Copyright (c) 2002 OpenBeOS Project 14 // 15 // Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. 16 // Copyright 1995-1997, Jon Watte 17 // 18 // Permission is hereby granted, free of charge, to any person obtaining a 19 // copy of this software and associated documentation files (the "Software"), 20 // to deal in the Software without restriction, including without limitation 21 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 22 // and/or sell copies of the Software, and to permit persons to whom the 23 // Software is furnished to do so, subject to the following conditions: 24 // 25 // The above copyright notice and this permission notice shall be included 26 // in all copies or substantial portions of the Software. 27 // 28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 29 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 30 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 31 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 32 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 33 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 34 // DEALINGS IN THE SOFTWARE. 35 /*****************************************************************************/ 36 37 #include <BitmapStream.h> 38 #include <Bitmap.h> 39 #include <Debug.h> 40 #include <string.h> 41 42 43 // --------------------------------------------------------------- 44 // Constructor 45 // 46 // Initializes this object to either use the BBitmap passed to 47 // it as the object to read/write to or to create a BBitmap 48 // when data is written to this object. 49 // 50 // Preconditions: 51 // 52 // Parameters: bitmap, the bitmap used to read from/write to, 53 // if it is NULL, a bitmap is created when 54 // this object is written to 55 // 56 // Postconditions: 57 // 58 // Returns: 59 // --------------------------------------------------------------- 60 BBitmapStream::BBitmapStream(BBitmap *bitmap) 61 { 62 fBitmap = bitmap; 63 fDetached = false; 64 fPosition = 0; 65 fSize = 0; 66 fpBigEndianHeader = new TranslatorBitmap; 67 68 // Extract header information if bitmap is available 69 if (fBitmap) { 70 fHeader.magic = B_TRANSLATOR_BITMAP; 71 fHeader.bounds = fBitmap->Bounds(); 72 fHeader.rowBytes = fBitmap->BytesPerRow(); 73 fHeader.colors = fBitmap->ColorSpace(); 74 fHeader.dataSize = static_cast<uint32> 75 ((fHeader.bounds.Height() + 1) * fHeader.rowBytes); 76 fSize = sizeof(TranslatorBitmap) + fHeader.dataSize; 77 78 if (B_HOST_IS_BENDIAN) 79 memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap)); 80 else 81 SwapHeader(&fHeader, fpBigEndianHeader); 82 } 83 } 84 85 // --------------------------------------------------------------- 86 // Destructor 87 // 88 // Destroys memory used by this object, but does not destroy the 89 // bitmap used by this object if it has been detached. This is so 90 // the user can use that bitmap after this object is destroyed. 91 // 92 // Preconditions: 93 // 94 // Parameters: 95 // 96 // Postconditions: 97 // 98 // Returns: 99 // --------------------------------------------------------------- 100 BBitmapStream::~BBitmapStream() 101 { 102 if (!fDetached) 103 delete fBitmap; 104 fBitmap = NULL; 105 106 delete fpBigEndianHeader; 107 fpBigEndianHeader = NULL; 108 } 109 110 // --------------------------------------------------------------- 111 // ReadAt 112 // 113 // Reads data from the stream at a specific position and for a 114 // specific amount. The first sizeof(TranslatorBitmap) bytes 115 // are the bitmap header. The header is always written out 116 // and read in as Big Endian byte order. 117 // 118 // Preconditions: 119 // 120 // Parameters: pos, the position in the stream to read from 121 // buffer, where the data will be read into 122 // size, the amount of data to read 123 // 124 // Postconditions: 125 // 126 // Returns: B_ERROR if there is no bitmap stored by the stream 127 // or if pos is a bad value, 128 // B_BAD_VALUE if buffer is NULL or pos is invalid 129 // or the amount read if the result >= 0 130 // --------------------------------------------------------------- 131 status_t 132 BBitmapStream::ReadAt(off_t pos, void *buffer, size_t size) 133 { 134 if (!fBitmap) 135 return B_ERROR; 136 if (!size) 137 return B_NO_ERROR; 138 if (pos >= fSize) 139 return B_ERROR; 140 if (!buffer || pos < 0) 141 return B_BAD_VALUE; 142 143 size_t toRead; 144 void *source; 145 146 if (pos < sizeof(TranslatorBitmap)) { 147 toRead = sizeof(TranslatorBitmap) - pos; 148 source = (reinterpret_cast<uint8 *> (fpBigEndianHeader)) + pos; 149 } else { 150 toRead = fSize - pos; 151 source = (reinterpret_cast<uint8 *> (fBitmap->Bits())) + pos - 152 sizeof(TranslatorBitmap); 153 } 154 if (toRead > size) 155 toRead = size; 156 157 memcpy(buffer, source, toRead); 158 return toRead; 159 } 160 161 // --------------------------------------------------------------- 162 // WriteAt 163 // 164 // Writes data to the bitmap from data, starting at position pos 165 // of size, size. The first sizeof(TranslatorBitmap) bytes 166 // of data must be the TranslatorBitmap header in the Big 167 // Endian byte order, otherwise, the data will fail to be 168 // successfully written. 169 // 170 // Preconditions: 171 // 172 // Parameters: pos, the position in the stream to write to 173 // data, the data to write to the stream 174 // size, the size of the data to write to the stream 175 // 176 // Postconditions: 177 // 178 // Returns: B_BAD_VALUE if size is bad or data is NULL or pos is invalid, 179 // B_MISMATCHED_VALUES if the bitmap header is bad, 180 // B_ERROR if error allocating memory or setting up 181 // big endian header, 182 // or the amount written if the result is >= 0 183 // --------------------------------------------------------------- 184 status_t 185 BBitmapStream::WriteAt(off_t pos, const void *data, size_t size) 186 { 187 if (!size) 188 return B_NO_ERROR; 189 if (!data || pos < 0 || pos > fSize) 190 return B_BAD_VALUE; 191 192 ssize_t written = 0; 193 while (size > 0) { 194 size_t toWrite; 195 void *dest; 196 // We depend on writing the header separately in detecting 197 // changes to it 198 if (pos < sizeof(TranslatorBitmap)) { 199 toWrite = sizeof(TranslatorBitmap) - pos; 200 dest = (reinterpret_cast<uint8 *> (&fHeader)) + pos; 201 } else { 202 toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap); 203 dest = (reinterpret_cast<uint8 *> (fBitmap->Bits())) + 204 pos - sizeof(TranslatorBitmap); 205 } 206 if (toWrite > size) 207 toWrite = size; 208 if (!toWrite && size) 209 // i.e. we've been told to write too much 210 return B_BAD_VALUE; 211 212 memcpy(dest, data, toWrite); 213 pos += toWrite; 214 written += toWrite; 215 data = (reinterpret_cast<const uint8 *> (data)) + toWrite; 216 size -= toWrite; 217 if (pos > fSize) 218 fSize = pos; 219 // If we change the header, the rest needs to be reset 220 if (pos == sizeof(TranslatorBitmap)) { 221 // Setup both host and Big Endian byte order bitmap headers 222 memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap)); 223 if (B_HOST_IS_LENDIAN) 224 SwapHeader(fpBigEndianHeader, &fHeader); 225 226 if (fBitmap && ((fBitmap->Bounds() != fHeader.bounds) || 227 (fBitmap->ColorSpace() != fHeader.colors) || 228 (fBitmap->BytesPerRow() != fHeader.rowBytes))) { 229 if (!fDetached) 230 // if someone detached, we don't delete 231 delete fBitmap; 232 fBitmap = NULL; 233 } 234 if (!fBitmap) { 235 if ((fHeader.bounds.left > 0.0) || (fHeader.bounds.top > 0.0)) 236 DEBUGGER("non-origin bounds!"); 237 fBitmap = new BBitmap(fHeader.bounds, fHeader.colors); 238 if (!fBitmap) 239 return B_ERROR; 240 if (fBitmap->BytesPerRow() != fHeader.rowBytes) 241 return B_MISMATCHED_VALUES; 242 } 243 if (fBitmap) 244 fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength(); 245 } 246 } 247 return written; 248 } 249 250 // --------------------------------------------------------------- 251 // Seek 252 // 253 // Changes the current stream position. 254 // 255 // Preconditions: 256 // 257 // Parameters: position, the position offset 258 // whence, decides how the position offset is used 259 // SEEK_CUR, position is added to current 260 // stream position 261 // SEEK_END, position is added to the end 262 // stream position 263 // SEEK_SET, the stream position is set to 264 // position 265 // 266 // Postconditions: 267 // 268 // Returns: B_BAD_VALUE if the position is bad 269 // or the new position value if the result >= 0 270 // --------------------------------------------------------------- 271 off_t 272 BBitmapStream::Seek(off_t position, uint32 whence) 273 { 274 // When whence == SEEK_SET, it just falls through to 275 // fPosition = position 276 if (whence == SEEK_CUR) 277 position += fPosition; 278 if (whence == SEEK_END) 279 position += fSize; 280 281 if (position < 0) 282 return B_BAD_VALUE; 283 if (position > fSize) 284 return B_BAD_VALUE; 285 286 fPosition = position; 287 return fPosition; 288 } 289 290 // --------------------------------------------------------------- 291 // Position 292 // 293 // Returns the current stream position 294 // 295 // Preconditions: 296 // 297 // Parameters: 298 // 299 // Postconditions: 300 // 301 // Returns: returns the curren stream position 302 // --------------------------------------------------------------- 303 off_t 304 BBitmapStream::Position() const 305 { 306 return fPosition; 307 } 308 309 310 // --------------------------------------------------------------- 311 // Size 312 // 313 // Returns the curren stream size 314 // 315 // Preconditions: 316 // 317 // Parameters: 318 // 319 // Postconditions: 320 // 321 // Returns: returns the current stream size 322 // --------------------------------------------------------------- 323 off_t 324 BBitmapStream::Size() const 325 { 326 return fSize; 327 } 328 329 // --------------------------------------------------------------- 330 // SetSize 331 // 332 // Sets the size of the data, but I'm not sure if this function 333 // has any real purpose. 334 // 335 // Preconditions: 336 // 337 // Parameters: size, the size to set the stream size to. 338 // 339 // Postconditions: 340 // 341 // Returns: B_BAD_VALUE, if size is a bad value 342 // B_NO_ERROR, if size is a valid value 343 // --------------------------------------------------------------- 344 status_t 345 BBitmapStream::SetSize(off_t size) 346 { 347 if (size < 0) 348 return B_BAD_VALUE; 349 if (fBitmap && (size > fHeader.dataSize + sizeof(TranslatorBitmap))) 350 return B_BAD_VALUE; 351 // Problem: 352 // What if someone calls SetSize() before writing the header, 353 // so we don't know what bitmap to create? 354 // Solution: 355 // We assume people will write the header before any data, 356 // so SetSize() is really not going to do anything. 357 if (fBitmap) 358 // if we checked that the size was OK 359 fSize = size; 360 361 return B_NO_ERROR; 362 } 363 364 // --------------------------------------------------------------- 365 // DetachBitmap 366 // 367 // Returns the internal bitmap through outBitmap so the user 368 // can do whatever they want to it. It means that when the 369 // BBitmapStream is deleted, the bitmap is not deleted. After 370 // the bitmap has been detached, it is still used by the stream, 371 // but it is never deleted by the stream. 372 // 373 // Preconditions: 374 // 375 // Parameters: outBitmap, where the bitmap is detached to 376 // 377 // Postconditions: 378 // 379 // Returns: B_BAD_VALUE, if outBitmap is NULL 380 // B_ERROR, if the bitmap is NULL or 381 // has already been detached 382 // B_NO_ERROR, if the bitmap was successfully detached 383 // --------------------------------------------------------------- 384 status_t 385 BBitmapStream::DetachBitmap(BBitmap **outBitmap) 386 { 387 if (!outBitmap) 388 return B_BAD_VALUE; 389 if (!fBitmap || fDetached) { 390 *outBitmap = NULL; 391 return B_ERROR; 392 } 393 394 fDetached = true; 395 *outBitmap = fBitmap; 396 397 return B_NO_ERROR; 398 } 399 400 // --------------------------------------------------------------- 401 // SwapHeader 402 // 403 // Swaps the byte order of source, no matter what the 404 // byte order, and copies the result to destination 405 // 406 // Preconditions: both parameters must not be null 407 // 408 // Parameters: source, data to be swapped 409 // 410 // destination, where the swapped data will 411 // be copied to 412 // 413 // Postconditions: 414 // 415 // Returns: 416 // 417 // --------------------------------------------------------------- 418 void 419 BBitmapStream::SwapHeader(const TranslatorBitmap *source, 420 TranslatorBitmap *destination) 421 { 422 memcpy(destination, source, sizeof(TranslatorBitmap)); 423 swap_data(B_UINT32_TYPE, destination, sizeof(TranslatorBitmap), 424 B_SWAP_ALWAYS); 425 } 426 427 // --------------------------------------------------------------- 428 // _ReservedBitmapStream1() 429 // 430 // It doesn't do anything :). Its here only for past/future 431 // binary compatibility. 432 // 433 // Preconditions: 434 // 435 // Parameters: 436 // 437 // Postconditions: 438 // 439 // Returns: 440 // --------------------------------------------------------------- 441 void 442 BBitmapStream::_ReservedBitmapStream1() 443 { 444 } 445 446 // --------------------------------------------------------------- 447 // _ReservedBitmapStream2() 448 // 449 // It doesn't do anything :). Its only here for past/future 450 // binary compatibility. 451 // 452 // Preconditions: 453 // 454 // Parameters: 455 // 456 // Postconditions: 457 // 458 // Returns: 459 // --------------------------------------------------------------- 460 void 461 BBitmapStream::_ReservedBitmapStream2() 462 { 463 } 464 465