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 *fBigEndianHeader = fHeader; 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 *fBigEndianHeader = fHeader; 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 0, fHeader.colors, fHeader.rowBytes); 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 BytesPerRow width %" B_PRId32 " does not match " 164 "value declared in header %" B_PRId32 "\n", 165 fBitmap->BytesPerRow(), fHeader.rowBytes); 166 return B_MISMATCHED_VALUES; 167 } 168 } 169 if (fBitmap != NULL) 170 fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength(); 171 } 172 } 173 return written; 174 } 175 176 177 // Changes the current stream position. 178 off_t 179 BBitmapStream::Seek(off_t position, uint32 seekMode) 180 { 181 // When whence == SEEK_SET, it just falls through to 182 // fPosition = position 183 if (seekMode == SEEK_CUR) 184 position += fPosition; 185 else if (seekMode == SEEK_END) 186 position += fSize; 187 188 if (position < 0 || position > (off_t)fSize) 189 return B_BAD_VALUE; 190 191 fPosition = position; 192 return fPosition; 193 } 194 195 196 // Returns the current stream position 197 off_t 198 BBitmapStream::Position() const 199 { 200 return fPosition; 201 } 202 203 204 205 // Returns the current stream size 206 off_t 207 BBitmapStream::Size() const 208 { 209 return fSize; 210 } 211 212 213 // Sets the size of the data. 214 // I'm not sure if this method has any real purpose. 215 status_t 216 BBitmapStream::SetSize(off_t size) 217 { 218 if (size < 0) 219 return B_BAD_VALUE; 220 if (fBitmap && (size > (off_t)(fHeader.dataSize + sizeof(TranslatorBitmap)))) 221 return B_BAD_VALUE; 222 // Problem: 223 // What if someone calls SetSize() before writing the header, 224 // so we don't know what bitmap to create? 225 // Solution: 226 // We assume people will write the header before any data, 227 // so SetSize() is really not going to do anything. 228 if (fBitmap != NULL) 229 fSize = size; 230 231 return B_NO_ERROR; 232 } 233 234 235 // Sets _bitmap to point to the internal bitmap object. 236 status_t 237 BBitmapStream::DetachBitmap(BBitmap** _bitmap) 238 { 239 if (_bitmap == NULL) 240 return B_BAD_VALUE; 241 if (!fBitmap || fDetached) 242 return B_ERROR; 243 244 fDetached = true; 245 *_bitmap = fBitmap; 246 247 return B_OK; 248 } 249 250 251 // Swaps the byte order of source, no matter the byte order, and 252 // copies the result to destination. 253 void 254 BBitmapStream::SwapHeader(const TranslatorBitmap* source, 255 TranslatorBitmap* destination) 256 { 257 if (source == NULL || destination == NULL) 258 return; 259 260 *destination = *source; 261 swap_data(B_UINT32_TYPE, destination, sizeof(TranslatorBitmap), 262 B_SWAP_ALWAYS); 263 } 264 265 266 void BBitmapStream::_ReservedBitmapStream1() {} 267 void BBitmapStream::_ReservedBitmapStream2() {} 268