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 = NULL; 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 SetBigEndianHeader(); 79 } 80 } 81 82 // --------------------------------------------------------------- 83 // Destructor 84 // 85 // Destroys memory used by this object, but does not destroy the 86 // bitmap used by this object if it has been detached. This is so 87 // the user can use that bitmap after this object is destroyed. 88 // 89 // Preconditions: 90 // 91 // Parameters: 92 // 93 // Postconditions: 94 // 95 // Returns: 96 // --------------------------------------------------------------- 97 BBitmapStream::~BBitmapStream() 98 { 99 if (fBitmap && !fDetached) 100 delete fBitmap; 101 102 if (fpBigEndianHeader) 103 delete fpBigEndianHeader; 104 } 105 106 // --------------------------------------------------------------- 107 // ReadAt 108 // 109 // Reads data from the stream at a specific position and for a 110 // specific amount. The first sizeof(TranslatorBitmap) bytes 111 // are the bitmap header. The header is always written out 112 // and read in as Big Endian byte order. 113 // 114 // Preconditions: 115 // 116 // Parameters: pos, the position in the stream to read from 117 // buffer, where the data will be read into 118 // size, the amount of data to read 119 // 120 // Postconditions: 121 // 122 // Returns: B_ERROR if there is no bitmap stored by the stream 123 // or if pos is a bad value, 124 // B_BAD_VALUE if buffer is NULL or pos is invalid 125 // or the amount read if the result >= 0 126 // --------------------------------------------------------------- 127 status_t 128 BBitmapStream::ReadAt(off_t pos, void *buffer, size_t size) 129 { 130 if (!buffer || pos < 0) 131 return B_BAD_VALUE; 132 if (!fBitmap || pos >= fSize) 133 return B_ERROR; 134 if (!size) 135 return B_NO_ERROR; 136 137 size_t toRead; 138 void *source; 139 140 if (pos < sizeof(TranslatorBitmap)) { 141 toRead = sizeof(TranslatorBitmap) - pos; 142 source = (reinterpret_cast<uint8 *> (fpBigEndianHeader)) + pos; 143 } else { 144 toRead = fSize - pos; 145 source = (reinterpret_cast<uint8 *> (fBitmap->Bits())) + pos - 146 sizeof(TranslatorBitmap); 147 } 148 if (toRead > size) 149 toRead = size; 150 151 memcpy(buffer, source, toRead); 152 return toRead; 153 } 154 155 // --------------------------------------------------------------- 156 // WriteAt 157 // 158 // Writes data to the bitmap from data, starting at position pos 159 // of size, size. The first sizeof(TranslatorBitmap) bytes 160 // of data must be the TranslatorBitmap header in the Big 161 // Endian byte order, otherwise, the data will fail to be 162 // successfully written. 163 // 164 // Preconditions: 165 // 166 // Parameters: pos, the position in the stream to write to 167 // data, the data to write to the stream 168 // size, the size of the data to write to the stream 169 // 170 // Postconditions: 171 // 172 // Returns: B_BAD_VALUE if size is bad or data is NULL or pos is invalid, 173 // B_MISMATCHED_VALUES if the bitmap header is bad, 174 // B_ERROR if error allocating memory or setting up 175 // big endian header, 176 // or the amount written if the result is >= 0 177 // --------------------------------------------------------------- 178 status_t 179 BBitmapStream::WriteAt(off_t pos, const void *data, size_t size) 180 { 181 if (!data || pos < 0 || pos > fSize) 182 return B_BAD_VALUE; 183 if (!size) 184 return B_NO_ERROR; 185 186 ssize_t written = 0; 187 while (size > 0) { 188 size_t toWrite; 189 void *dest; 190 // We depend on writing the header separately in detecting 191 // changes to it 192 if (pos < sizeof(TranslatorBitmap)) { 193 toWrite = sizeof(TranslatorBitmap) - pos; 194 dest = (reinterpret_cast<uint8 *> (&fHeader)) + pos; 195 } else { 196 toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap); 197 dest = (reinterpret_cast<uint8 *> (fBitmap->Bits())) + 198 pos - sizeof(TranslatorBitmap); 199 } 200 if (toWrite > size) 201 toWrite = size; 202 if (!toWrite && size) 203 // i.e. we've been told to write too much 204 return B_BAD_VALUE; 205 206 memcpy(dest, data, toWrite); 207 pos += toWrite; 208 written += toWrite; 209 data = (reinterpret_cast<const uint8 *> (data)) + toWrite; 210 size -= toWrite; 211 if (pos > fSize) 212 fSize = pos; 213 // If we change the header, the rest needs to be reset 214 if (pos == sizeof(TranslatorBitmap)) { 215 // Setup both host and Big Endian byte order bitmap headers 216 if (ConvertBEndianToHost(&fHeader) != B_OK) 217 return B_ERROR; 218 if (SetBigEndianHeader() != B_OK) 219 return B_ERROR; 220 221 if (fBitmap && ((fBitmap->Bounds() != fHeader.bounds) || 222 (fBitmap->ColorSpace() != fHeader.colors) || 223 (fBitmap->BytesPerRow() != fHeader.rowBytes))) { 224 if (!fDetached) 225 // if someone detached, we don't delete 226 delete fBitmap; 227 fBitmap = NULL; 228 } 229 if (!fBitmap) { 230 if ((fHeader.bounds.left > 0.0) || (fHeader.bounds.top > 0.0)) 231 DEBUGGER("non-origin bounds!"); 232 fBitmap = new BBitmap(fHeader.bounds, fHeader.colors); 233 if (!fBitmap) 234 return B_ERROR; 235 if (fBitmap->BytesPerRow() != fHeader.rowBytes) 236 return B_MISMATCHED_VALUES; 237 } 238 if (fBitmap) 239 fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength(); 240 } 241 } 242 return written; 243 } 244 245 // --------------------------------------------------------------- 246 // Seek 247 // 248 // Changes the current stream position. 249 // 250 // Preconditions: 251 // 252 // Parameters: position, the position offset 253 // whence, decides how the position offset is used 254 // SEEK_CUR, position is added to current 255 // stream position 256 // SEEK_END, position is added to the end 257 // stream position 258 // SEEK_SET, the stream position is set to 259 // position 260 // 261 // Postconditions: 262 // 263 // Returns: B_BAD_VALUE if the position is bad 264 // or the new position value if the result >= 0 265 // --------------------------------------------------------------- 266 off_t 267 BBitmapStream::Seek(off_t position, uint32 whence) 268 { 269 // When whence == SEEK_SET, it just falls through to 270 // fPosition = position 271 if (whence == SEEK_CUR) 272 position += fPosition; 273 if (whence == SEEK_END) 274 position += fSize; 275 276 if (position < 0) 277 return B_BAD_VALUE; 278 if (position > fSize) 279 return B_BAD_VALUE; 280 281 fPosition = position; 282 return fPosition; 283 } 284 285 // --------------------------------------------------------------- 286 // Position 287 // 288 // Returns the current stream position 289 // 290 // Preconditions: 291 // 292 // Parameters: 293 // 294 // Postconditions: 295 // 296 // Returns: returns the curren stream position 297 // --------------------------------------------------------------- 298 off_t 299 BBitmapStream::Position() const 300 { 301 return fPosition; 302 } 303 304 305 // --------------------------------------------------------------- 306 // Size 307 // 308 // Returns the curren stream size 309 // 310 // Preconditions: 311 // 312 // Parameters: 313 // 314 // Postconditions: 315 // 316 // Returns: returns the current stream size 317 // --------------------------------------------------------------- 318 off_t 319 BBitmapStream::Size() const 320 { 321 return fSize; 322 } 323 324 // --------------------------------------------------------------- 325 // SetSize 326 // 327 // Sets the size of the data, but I'm not sure if this function 328 // has any real purpose. 329 // 330 // Preconditions: 331 // 332 // Parameters: size, the size to set the stream size to. 333 // 334 // Postconditions: 335 // 336 // Returns: B_BAD_VALUE, if size is a bad value 337 // B_NO_ERROR, if size is a valid value 338 // --------------------------------------------------------------- 339 status_t 340 BBitmapStream::SetSize(off_t size) 341 { 342 if (size < 0) 343 return B_BAD_VALUE; 344 if (fBitmap && (size > fHeader.dataSize + sizeof(TranslatorBitmap))) 345 return B_BAD_VALUE; 346 // Problem: 347 // What if someone calls SetSize() before writing the header, 348 // so we don't know what bitmap to create? 349 // Solution: 350 // We assume people will write the header before any data, 351 // so SetSize() is really not going to do anything. 352 if (fBitmap) 353 // if we checked that the size was OK 354 fSize = size; 355 356 return B_NO_ERROR; 357 } 358 359 // --------------------------------------------------------------- 360 // DetachBitmap 361 // 362 // Returns the internal bitmap through outBitmap so the user 363 // can do whatever they want to it. It means that when the 364 // BBitmapStream is deleted, the bitmap is not deleted. After 365 // the bitmap has been detached, it is still used by the stream, 366 // but it is never deleted by the stream. 367 // 368 // Preconditions: 369 // 370 // Parameters: outBitmap, where the bitmap is detached to 371 // 372 // Postconditions: 373 // 374 // Returns: B_BAD_VALUE, if outBitmap is NULL 375 // B_ERROR, if the bitmap is NULL or 376 // has already been detached 377 // B_NO_ERROR, if the bitmap was successfully detached 378 // --------------------------------------------------------------- 379 status_t 380 BBitmapStream::DetachBitmap(BBitmap **outBitmap) 381 { 382 if (!outBitmap) 383 return B_BAD_VALUE; 384 if (fDetached || !fBitmap) 385 return B_ERROR; 386 387 fDetached = true; 388 *outBitmap = fBitmap; 389 390 return B_NO_ERROR; 391 } 392 393 // --------------------------------------------------------------- 394 // ConvertBEndianToHost 395 // 396 // This static function converts a TranslatorBitmap from Big 397 // Endian byte order to the host byte order. 398 // 399 // Preconditions: Data pointed to by pheader must be in 400 // Big Endian byte order 401 // 402 // Parameters: pheader, the TranslatorBitmap structure to convert 403 // 404 // Postconditions: 405 // 406 // Returns: B_OK, if the byte swap succeeded 407 // B_BAD_VALUE, if pheader is NULL, 408 // or the byte swap failed 409 // --------------------------------------------------------------- 410 status_t 411 BBitmapStream::ConvertBEndianToHost(TranslatorBitmap *pheader) 412 { 413 if (!pheader) 414 return B_BAD_VALUE; 415 416 return swap_data(B_UINT32_TYPE, pheader, sizeof(TranslatorBitmap), 417 B_SWAP_BENDIAN_TO_HOST); 418 } 419 420 // --------------------------------------------------------------- 421 // SetBigEndianHeader 422 // 423 // Assigns fpBigEndianHeader to the Big Endian byte order version 424 // of fHeader, the bitmap header information. fpBigEndianHeader is 425 // used by ReadAt() to send out the bitmap header in the Big 426 // Endian byte order. 427 // 428 // Preconditions: fHeader must be in the host byte order for 429 // this function to work properly 430 // 431 // Parameters: 432 // 433 // Postconditions: 434 // 435 // Returns: B_OK, if the byte swap succeeded 436 // B_ERROR, if failed to allocate memory for 437 // big endian header 438 // B_BAD_VALUE, if the byte swap failed 439 // --------------------------------------------------------------- 440 status_t 441 BBitmapStream::SetBigEndianHeader() 442 { 443 if (!fpBigEndianHeader) { 444 fpBigEndianHeader = new TranslatorBitmap; 445 if (!fpBigEndianHeader) 446 return B_ERROR; 447 } 448 449 fpBigEndianHeader->magic = fHeader.magic; 450 fpBigEndianHeader->bounds = fHeader.bounds; 451 fpBigEndianHeader->rowBytes = fHeader.rowBytes; 452 fpBigEndianHeader->colors = fHeader.colors; 453 fpBigEndianHeader->dataSize = fHeader.dataSize; 454 455 return swap_data(B_UINT32_TYPE, fpBigEndianHeader, 456 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN); 457 } 458 459 // --------------------------------------------------------------- 460 // _ReservedBitmapStream1() 461 // 462 // It doesn't do anything :). Its here only for past/future 463 // binary compatibility. 464 // 465 // Preconditions: 466 // 467 // Parameters: 468 // 469 // Postconditions: 470 // 471 // Returns: 472 // --------------------------------------------------------------- 473 void 474 BBitmapStream::_ReservedBitmapStream1() 475 { 476 } 477 478 // --------------------------------------------------------------- 479 // _ReservedBitmapStream2() 480 // 481 // It doesn't do anything :). Its only here for past/future 482 // binary compatibility. 483 // 484 // Preconditions: 485 // 486 // Parameters: 487 // 488 // Postconditions: 489 // 490 // Returns: 491 // --------------------------------------------------------------- 492 void 493 BBitmapStream::_ReservedBitmapStream2() 494 { 495 } 496 497