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