xref: /haiku/src/kits/translation/BitmapStream.cpp (revision 7120e97489acbf17d86d3f33e3b2e68974fd4b23)
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