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