1 /*****************************************************************************/ 2 // Copyright (c) 2002-2005 Haiku Project 3 // 4 // Reimplemented by: Travis Smith, Michael Wilber, Translation Kit Team 5 // 6 // Description: BPositionIO based object to read/write bitmap format to/from 7 // a BBitmap object. 8 // 9 // The BTranslationUtils class uses this object and makes it 10 // easy for users to load bitmaps. 11 // 12 // Original Version: Copyright 1998, Be Incorporated, All Rights Reserved. 13 // Copyright 1995-1997, Jon Watte 14 // 15 // Permission is hereby granted, free of charge, to any person obtaining a 16 // copy of this software and associated documentation files (the "Software"), 17 // to deal in the Software without restriction, including without limitation 18 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 // and/or sell copies of the Software, and to permit persons to whom the 20 // Software is furnished to do so, subject to the following conditions: 21 // 22 // The above copyright notice and this permission notice shall be included 23 // in all copies or substantial portions of the Software. 24 // 25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 26 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 // DEALINGS IN THE SOFTWARE. 32 /*****************************************************************************/ 33 34 #include <BitmapStream.h> 35 #include <Bitmap.h> 36 #include <Debug.h> 37 #include <string.h> 38 39 40 // --------------------------------------------------------------- 41 // Constructor 42 // 43 // Initializes this object to either use the BBitmap passed to 44 // it as the object to read/write to or to create a BBitmap 45 // when data is written to this object. 46 // 47 // Preconditions: 48 // 49 // Parameters: bitmap, the bitmap used to read from/write to, 50 // if it is NULL, a bitmap is created when 51 // this object is written to 52 // 53 // Postconditions: 54 // 55 // Returns: 56 // --------------------------------------------------------------- 57 BBitmapStream::BBitmapStream(BBitmap *bitmap) 58 { 59 fBitmap = bitmap; 60 fDetached = false; 61 fPosition = 0; 62 fSize = 0; 63 fpBigEndianHeader = new TranslatorBitmap; 64 65 // Extract header information if bitmap is available 66 if (fBitmap) { 67 fHeader.magic = B_TRANSLATOR_BITMAP; 68 fHeader.bounds = fBitmap->Bounds(); 69 fHeader.rowBytes = fBitmap->BytesPerRow(); 70 fHeader.colors = fBitmap->ColorSpace(); 71 fHeader.dataSize = static_cast<uint32> 72 ((fHeader.bounds.Height() + 1) * fHeader.rowBytes); 73 fSize = sizeof(TranslatorBitmap) + fHeader.dataSize; 74 75 if (B_HOST_IS_BENDIAN) 76 memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap)); 77 else 78 SwapHeader(&fHeader, fpBigEndianHeader); 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 (!fDetached) 100 delete fBitmap; 101 fBitmap = NULL; 102 103 delete fpBigEndianHeader; 104 fpBigEndianHeader = NULL; 105 } 106 107 // --------------------------------------------------------------- 108 // ReadAt 109 // 110 // Reads data from the stream at a specific position and for a 111 // specific amount. The first sizeof(TranslatorBitmap) bytes 112 // are the bitmap header. The header is always written out 113 // and read in as Big Endian byte order. 114 // 115 // Preconditions: 116 // 117 // Parameters: pos, the position in the stream to read from 118 // buffer, where the data will be read into 119 // size, the amount of data to read 120 // 121 // Postconditions: 122 // 123 // Returns: B_ERROR if there is no bitmap stored by the stream 124 // or if pos is a bad value, 125 // B_BAD_VALUE if buffer is NULL or pos is invalid 126 // or the amount read if the result >= 0 127 // --------------------------------------------------------------- 128 ssize_t 129 BBitmapStream::ReadAt(off_t pos, void *buffer, size_t size) 130 { 131 if (!fBitmap) 132 return B_ERROR; 133 if (!size) 134 return B_NO_ERROR; 135 if (pos >= fSize) 136 return B_ERROR; 137 if (!buffer || pos < 0) 138 return B_BAD_VALUE; 139 140 ssize_t toRead; 141 void *source; 142 143 if (pos < sizeof(TranslatorBitmap)) { 144 toRead = sizeof(TranslatorBitmap) - pos; 145 source = (reinterpret_cast<uint8 *>(fpBigEndianHeader)) + pos; 146 } else { 147 toRead = fSize - pos; 148 source = (reinterpret_cast<uint8 *>(fBitmap->Bits())) + pos - 149 sizeof(TranslatorBitmap); 150 } 151 if (toRead > (ssize_t)size) 152 toRead = (ssize_t)size; 153 154 memcpy(buffer, source, toRead); 155 return toRead; 156 } 157 158 // --------------------------------------------------------------- 159 // WriteAt 160 // 161 // Writes data to the bitmap from data, starting at position pos 162 // of size, size. The first sizeof(TranslatorBitmap) bytes 163 // of data must be the TranslatorBitmap header in the Big 164 // Endian byte order, otherwise, the data will fail to be 165 // successfully written. 166 // 167 // Preconditions: 168 // 169 // Parameters: pos, the position in the stream to write to 170 // data, the data to write to the stream 171 // size, the size of the data to write to the stream 172 // 173 // Postconditions: 174 // 175 // Returns: B_BAD_VALUE if size is bad or data is NULL or pos is invalid, 176 // B_MISMATCHED_VALUES if the bitmap header is bad, 177 // B_ERROR if error allocating memory or setting up 178 // big endian header, 179 // or the amount written if the result is >= 0 180 // --------------------------------------------------------------- 181 ssize_t 182 BBitmapStream::WriteAt(off_t pos, const void *data, size_t size) 183 { 184 if (!size) 185 return B_NO_ERROR; 186 if (!data || pos < 0 || pos > fSize) 187 return B_BAD_VALUE; 188 189 ssize_t written = 0; 190 while (size > 0) { 191 size_t toWrite; 192 void *dest; 193 // We depend on writing the header separately in detecting 194 // changes to it 195 if (pos < sizeof(TranslatorBitmap)) { 196 toWrite = sizeof(TranslatorBitmap) - pos; 197 dest = (reinterpret_cast<uint8 *> (&fHeader)) + pos; 198 } else { 199 toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap); 200 dest = (reinterpret_cast<uint8 *> (fBitmap->Bits())) + 201 pos - sizeof(TranslatorBitmap); 202 } 203 if (toWrite > size) 204 toWrite = size; 205 if (!toWrite && size) 206 // i.e. we've been told to write too much 207 return B_BAD_VALUE; 208 209 memcpy(dest, data, toWrite); 210 pos += toWrite; 211 written += toWrite; 212 data = (reinterpret_cast<const uint8 *> (data)) + toWrite; 213 size -= toWrite; 214 if (pos > fSize) 215 fSize = pos; 216 // If we change the header, the rest needs to be reset 217 if (pos == sizeof(TranslatorBitmap)) { 218 // Setup both host and Big Endian byte order bitmap headers 219 memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap)); 220 if (B_HOST_IS_LENDIAN) 221 SwapHeader(fpBigEndianHeader, &fHeader); 222 223 if (fBitmap 224 && (fBitmap->Bounds() != fHeader.bounds 225 || fBitmap->ColorSpace() != fHeader.colors 226 || (uint32)fBitmap->BytesPerRow() != fHeader.rowBytes)) { 227 if (!fDetached) 228 // if someone detached, we don't delete 229 delete fBitmap; 230 fBitmap = NULL; 231 } 232 if (!fBitmap) { 233 if (fHeader.bounds.left > 0.0 || fHeader.bounds.top > 0.0) 234 DEBUGGER("non-origin bounds!"); 235 fBitmap = new BBitmap(fHeader.bounds, fHeader.colors); 236 if (!fBitmap) 237 return B_ERROR; 238 if ((uint32)fBitmap->BytesPerRow() != fHeader.rowBytes) { 239 fprintf(stderr, "BitmapStream %ld %ld\n", fBitmap->BytesPerRow(), fHeader.rowBytes); 240 return B_MISMATCHED_VALUES; 241 } 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