xref: /haiku/src/kits/translation/BitmapStream.cpp (revision 9eb55bc1d104b8fda80898f8b25c94d8000c8255)
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 = new TranslatorBitmap;
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 		if (B_HOST_IS_BENDIAN)
79 			memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap));
80 		else
81 			SwapHeader(&fHeader, fpBigEndianHeader);
82 	}
83 }
84 
85 // ---------------------------------------------------------------
86 // Destructor
87 //
88 // Destroys memory used by this object, but does not destroy the
89 // bitmap used by this object if it has been detached. This is so
90 // the user can use that bitmap after this object is destroyed.
91 //
92 // Preconditions:
93 //
94 // Parameters:
95 //
96 // Postconditions:
97 //
98 // Returns:
99 // ---------------------------------------------------------------
100 BBitmapStream::~BBitmapStream()
101 {
102 	if (!fDetached)
103 		delete fBitmap;
104 	fBitmap = NULL;
105 
106 	delete fpBigEndianHeader;
107 	fpBigEndianHeader = NULL;
108 }
109 
110 // ---------------------------------------------------------------
111 // ReadAt
112 //
113 // Reads data from the stream at a specific position and for a
114 // specific amount. The first sizeof(TranslatorBitmap) bytes
115 // are the bitmap header. The header is always written out
116 // and read in as Big Endian byte order.
117 //
118 // Preconditions:
119 //
120 // Parameters: pos, the position in the stream to read from
121 //             buffer, where the data will be read into
122 //             size, the amount of data to read
123 //
124 // Postconditions:
125 //
126 // Returns: B_ERROR if there is no bitmap stored by the stream
127 //                  or if pos is a bad value,
128 //          B_BAD_VALUE if buffer is NULL or pos is invalid
129 //          or the amount read if the result >= 0
130 // ---------------------------------------------------------------
131 status_t
132 BBitmapStream::ReadAt(off_t pos, void *buffer, size_t size)
133 {
134 	if (!fBitmap)
135 		return B_ERROR;
136 	if (!size)
137 		return B_NO_ERROR;
138 	if (pos >= fSize)
139 		return B_ERROR;
140 	if (!buffer || pos < 0)
141 		return B_BAD_VALUE;
142 
143 	size_t toRead;
144 	void *source;
145 
146 	if (pos < sizeof(TranslatorBitmap)) {
147 		toRead = sizeof(TranslatorBitmap) - pos;
148 		source = (reinterpret_cast<uint8 *> (fpBigEndianHeader)) + pos;
149 	} else {
150 		toRead = fSize - pos;
151 		source = (reinterpret_cast<uint8 *> (fBitmap->Bits())) + pos -
152 			sizeof(TranslatorBitmap);
153 	}
154 	if (toRead > size)
155 		toRead = size;
156 
157 	memcpy(buffer, source, toRead);
158 	return toRead;
159 }
160 
161 // ---------------------------------------------------------------
162 // WriteAt
163 //
164 // Writes data to the bitmap from data, starting at position pos
165 // of size, size. The first sizeof(TranslatorBitmap) bytes
166 // of data must be the TranslatorBitmap header in the Big
167 // Endian byte order, otherwise, the data will fail to be
168 // successfully written.
169 //
170 // Preconditions:
171 //
172 // Parameters: pos, the position in the stream to write to
173 //             data, the data to write to the stream
174 //             size, the size of the data to write to the stream
175 //
176 // Postconditions:
177 //
178 // Returns: B_BAD_VALUE if size is bad or data is NULL or pos is invalid,
179 //          B_MISMATCHED_VALUES if the bitmap header is bad,
180 //			B_ERROR if error allocating memory or setting up
181 //			        big endian header,
182 //          or the amount written if the result is >= 0
183 // ---------------------------------------------------------------
184 status_t
185 BBitmapStream::WriteAt(off_t pos, const void *data, size_t size)
186 {
187 	if (!size)
188 		return B_NO_ERROR;
189 	if (!data || pos < 0 || pos > fSize)
190 		return B_BAD_VALUE;
191 
192 	ssize_t written = 0;
193 	while (size > 0) {
194 		size_t toWrite;
195 		void *dest;
196 		// We depend on writing the header separately in detecting
197 		// changes to it
198 		if (pos < sizeof(TranslatorBitmap)) {
199 			toWrite = sizeof(TranslatorBitmap) - pos;
200 			dest = (reinterpret_cast<uint8 *> (&fHeader)) + pos;
201 		} else {
202 			toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap);
203 			dest = (reinterpret_cast<uint8 *> (fBitmap->Bits())) +
204 				pos - sizeof(TranslatorBitmap);
205 		}
206 		if (toWrite > size)
207 			toWrite = size;
208 		if (!toWrite && size)
209 			// i.e. we've been told to write too much
210 			return B_BAD_VALUE;
211 
212 		memcpy(dest, data, toWrite);
213 		pos += toWrite;
214 		written += toWrite;
215 		data = (reinterpret_cast<const uint8 *> (data)) + toWrite;
216 		size -= toWrite;
217 		if (pos > fSize)
218 			fSize = pos;
219 		// If we change the header, the rest needs to be reset
220 		if (pos == sizeof(TranslatorBitmap)) {
221 			// Setup both host and Big Endian byte order bitmap headers
222 			memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap));
223 			if (B_HOST_IS_LENDIAN)
224 				SwapHeader(fpBigEndianHeader, &fHeader);
225 
226 			if (fBitmap && ((fBitmap->Bounds() != fHeader.bounds) ||
227 					(fBitmap->ColorSpace() != fHeader.colors) ||
228 					(fBitmap->BytesPerRow() != fHeader.rowBytes))) {
229 				if (!fDetached)
230 					// if someone detached, we don't delete
231 					delete fBitmap;
232 				fBitmap = NULL;
233 			}
234 			if (!fBitmap) {
235 				if ((fHeader.bounds.left > 0.0) || (fHeader.bounds.top > 0.0))
236 					DEBUGGER("non-origin bounds!");
237 				fBitmap = new BBitmap(fHeader.bounds, fHeader.colors);
238 				if (!fBitmap)
239 					return B_ERROR;
240 				if (fBitmap->BytesPerRow() != fHeader.rowBytes)
241 					return B_MISMATCHED_VALUES;
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