1 /*****************************************************************************/ 2 // File: BitmapStream.cpp 3 // Class: BBitmapStream 4 // Reimplimented by: Travis Smith, Michael Wilber, Translation Kit Team 5 // Reimplimentation: 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 = (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 = ((uint8 *) fpBigEndianHeader) + pos; 143 } else { 144 toRead = fSize - pos; 145 source = ((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 = ((uint8 *) &fHeader) + pos; 195 } else { 196 toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap); 197 dest = ((uint8 *) fBitmap->Bits()) + pos - sizeof(TranslatorBitmap); 198 } 199 if (toWrite > size) 200 toWrite = size; 201 if (!toWrite && size) 202 // i.e. we've been told to write too much 203 return B_BAD_VALUE; 204 205 memcpy(dest, data, toWrite); 206 pos += toWrite; 207 written += toWrite; 208 data = ((uint8 *) data) + toWrite; 209 size -= toWrite; 210 if (pos > fSize) 211 fSize = pos; 212 // If we change the header, the rest needs to be reset 213 if (pos == sizeof(TranslatorBitmap)) { 214 // Setup both host and Big Endian byte order bitmap headers 215 if (ConvertBEndianToHost(&fHeader) != B_OK) 216 return B_ERROR; 217 if (SetBigEndianHeader() != B_OK) 218 return B_ERROR; 219 220 if (fBitmap && ((fBitmap->Bounds() != fHeader.bounds) || 221 (fBitmap->ColorSpace() != fHeader.colors) || 222 (fBitmap->BytesPerRow() != fHeader.rowBytes))) { 223 if (!fDetached) 224 // if someone detached, we don't delete 225 delete fBitmap; 226 fBitmap = NULL; 227 } 228 if (!fBitmap) { 229 if ((fHeader.bounds.left > 0.0) || (fHeader.bounds.top > 0.0)) 230 DEBUGGER("non-origin bounds!"); 231 fBitmap = new BBitmap(fHeader.bounds, fHeader.colors); 232 if (!fBitmap) 233 return B_ERROR; 234 if (fBitmap->BytesPerRow() != fHeader.rowBytes) 235 return B_MISMATCHED_VALUES; 236 } 237 if (fBitmap) 238 fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength(); 239 } 240 } 241 return written; 242 } 243 244 // --------------------------------------------------------------- 245 // Seek 246 // 247 // Changes the current stream position. 248 // 249 // Preconditions: 250 // 251 // Parameters: position, the position offset 252 // whence, decides how the position offset is used 253 // SEEK_CUR, position is added to current 254 // stream position 255 // SEEK_END, position is added to the end 256 // stream position 257 // SEEK_SET, the stream position is set to 258 // position 259 // 260 // Postconditions: 261 // 262 // Returns: B_BAD_VALUE if the position is bad 263 // or the new position value if the result >= 0 264 // --------------------------------------------------------------- 265 off_t 266 BBitmapStream::Seek(off_t position, uint32 whence) 267 { 268 // When whence == SEEK_SET, it just falls through to 269 // fPosition = position 270 if (whence == SEEK_CUR) 271 position += fPosition; 272 if (whence == SEEK_END) 273 position += fSize; 274 275 if (position < 0) 276 return B_BAD_VALUE; 277 if (position > fSize) 278 return B_BAD_VALUE; 279 280 fPosition = position; 281 return fPosition; 282 } 283 284 // --------------------------------------------------------------- 285 // Position 286 // 287 // Returns the current stream position 288 // 289 // Preconditions: 290 // 291 // Parameters: 292 // 293 // Postconditions: 294 // 295 // Returns: returns the curren stream position 296 // --------------------------------------------------------------- 297 off_t 298 BBitmapStream::Position() const 299 { 300 return fPosition; 301 } 302 303 304 // --------------------------------------------------------------- 305 // Size 306 // 307 // Returns the curren stream size 308 // 309 // Preconditions: 310 // 311 // Parameters: 312 // 313 // Postconditions: 314 // 315 // Returns: returns the current stream size 316 // --------------------------------------------------------------- 317 off_t 318 BBitmapStream::Size() const 319 { 320 return fSize; 321 } 322 323 // --------------------------------------------------------------- 324 // SetSize 325 // 326 // Sets the size of the data, but I'm not sure if this function 327 // has any real purpose. 328 // 329 // Preconditions: 330 // 331 // Parameters: size, the size to set the stream size to. 332 // 333 // Postconditions: 334 // 335 // Returns: B_BAD_VALUE, if size is a bad value 336 // B_NO_ERROR, if size is a valid value 337 // --------------------------------------------------------------- 338 status_t 339 BBitmapStream::SetSize(off_t size) 340 { 341 if (size < 0) 342 return B_BAD_VALUE; 343 if (fBitmap && (size > fHeader.dataSize + sizeof(TranslatorBitmap))) 344 return B_BAD_VALUE; 345 // Problem: 346 // What if someone calls SetSize() before writing the header, 347 // so we don't know what bitmap to create? 348 // Solution: 349 // We assume people will write the header before any data, 350 // so SetSize() is really not going to do anything. 351 if (fBitmap) 352 // if we checked that the size was OK 353 fSize = size; 354 355 return B_NO_ERROR; 356 } 357 358 // --------------------------------------------------------------- 359 // DetachBitmap 360 // 361 // Returns the internal bitmap through outBitmap so the user 362 // can do whatever they want to it. It means that when the 363 // BBitmapStream is deleted, the bitmap is not deleted. After 364 // the bitmap has been detached, it is still used by the stream, 365 // but it is never deleted by the stream. 366 // 367 // Preconditions: 368 // 369 // Parameters: outBitmap, where the bitmap is detached to 370 // 371 // Postconditions: 372 // 373 // Returns: B_BAD_VALUE, if outBitmap is NULL 374 // B_ERROR, if the bitmap is NULL or 375 // has already been detached 376 // B_NO_ERROR, if the bitmap was successfully detached 377 // --------------------------------------------------------------- 378 status_t 379 BBitmapStream::DetachBitmap(BBitmap **outBitmap) 380 { 381 if (!outBitmap) 382 return B_BAD_VALUE; 383 if (fDetached || !fBitmap) 384 return B_ERROR; 385 386 fDetached = true; 387 *outBitmap = fBitmap; 388 389 return B_NO_ERROR; 390 } 391 392 // --------------------------------------------------------------- 393 // ConvertBEndianToHost 394 // 395 // This static function converts a TranslatorBitmap from Big 396 // Endian byte order to the host byte order. 397 // 398 // Preconditions: Data pointed to by pheader must be in 399 // Big Endian byte order 400 // 401 // Parameters: pheader, the TranslatorBitmap structure to convert 402 // 403 // Postconditions: 404 // 405 // Returns: B_OK, if the byte swap succeeded 406 // B_BAD_VALUE, if pheader is NULL, 407 // or the byte swap failed 408 // --------------------------------------------------------------- 409 status_t 410 BBitmapStream::ConvertBEndianToHost(TranslatorBitmap *pheader) 411 { 412 if (!pheader) 413 return B_BAD_VALUE; 414 415 return swap_data(B_UINT32_TYPE, pheader, sizeof(TranslatorBitmap), 416 B_SWAP_BENDIAN_TO_HOST); 417 } 418 419 // --------------------------------------------------------------- 420 // SetBigEndianHeader 421 // 422 // Assigns fpBigEndianHeader to the Big Endian byte order version 423 // of fHeader, the bitmap header information. fpBigEndianHeader is 424 // used by ReadAt() to send out the bitmap header in the Big 425 // Endian byte order. 426 // 427 // Preconditions: fHeader must be in the host byte order for 428 // this function to work properly 429 // 430 // Parameters: 431 // 432 // Postconditions: 433 // 434 // Returns: B_OK, if the byte swap succeeded 435 // B_ERROR, if failed to allocate memory for 436 // big endian header 437 // B_BAD_VALUE, if the byte swap failed 438 // --------------------------------------------------------------- 439 status_t 440 BBitmapStream::SetBigEndianHeader() 441 { 442 if (!fpBigEndianHeader) { 443 fpBigEndianHeader = new TranslatorBitmap; 444 if (!fpBigEndianHeader) 445 return B_ERROR; 446 } 447 448 fpBigEndianHeader->magic = fHeader.magic; 449 fpBigEndianHeader->bounds = fHeader.bounds; 450 fpBigEndianHeader->rowBytes = fHeader.rowBytes; 451 fpBigEndianHeader->colors = fHeader.colors; 452 fpBigEndianHeader->dataSize = fHeader.dataSize; 453 454 return swap_data(B_UINT32_TYPE, fpBigEndianHeader, 455 sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN); 456 } 457 458 // --------------------------------------------------------------- 459 // _ReservedBitmapStream1() 460 // 461 // It doesn't do anything :). Its here only for past/future 462 // binary compatibility. 463 // 464 // Preconditions: 465 // 466 // Parameters: 467 // 468 // Postconditions: 469 // 470 // Returns: 471 // --------------------------------------------------------------- 472 void 473 BBitmapStream::_ReservedBitmapStream1() 474 { 475 } 476 477 // --------------------------------------------------------------- 478 // _ReservedBitmapStream2() 479 // 480 // It doesn't do anything :). Its only here for past/future 481 // binary compatibility. 482 // 483 // Preconditions: 484 // 485 // Parameters: 486 // 487 // Postconditions: 488 // 489 // Returns: 490 // --------------------------------------------------------------- 491 void 492 BBitmapStream::_ReservedBitmapStream2() 493 { 494 } 495 496