xref: /haiku/src/kits/translation/BitmapStream.cpp (revision 0dacda17d52333639ef3874b7e67702b646a5672)
1 /*****************************************************************************/
2 // Copyright (c) 2002-2005 Haiku Project
3 //
4 // Reimplemented by: Travis Smith, Michael Wilber, Translation Kit Team
5 //
6 // Description: BPositionIO based object to read/write bitmap format to/from
7 //              a BBitmap object.
8 //
9 //              The BTranslationUtils class uses this object and makes it
10 //              easy for users to load bitmaps.
11 //
12 // Original Version: Copyright 1998, Be Incorporated, All Rights Reserved.
13 //                   Copyright 1995-1997, Jon Watte
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining a
16 // copy of this software and associated documentation files (the "Software"),
17 // to deal in the Software without restriction, including without limitation
18 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 // and/or sell copies of the Software, and to permit persons to whom the
20 // Software is furnished to do so, subject to the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be included
23 // in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 // DEALINGS IN THE SOFTWARE.
32 /*****************************************************************************/
33 
34 #include <BitmapStream.h>
35 #include <Bitmap.h>
36 #include <Debug.h>
37 #include <string.h>
38 
39 
40 // ---------------------------------------------------------------
41 // Constructor
42 //
43 // Initializes this object to either use the BBitmap passed to
44 // it as the object to read/write to or to create a BBitmap
45 // when data is written to this object.
46 //
47 // Preconditions:
48 //
49 // Parameters: bitmap, the bitmap used to read from/write to,
50 //                     if it is NULL, a bitmap is created when
51 //                     this object is written to
52 //
53 // Postconditions:
54 //
55 // Returns:
56 // ---------------------------------------------------------------
57 BBitmapStream::BBitmapStream(BBitmap *bitmap)
58 {
59 	fBitmap = bitmap;
60 	fDetached = false;
61 	fPosition = 0;
62 	fSize = 0;
63 	fpBigEndianHeader = new TranslatorBitmap;
64 
65 	// Extract header information if bitmap is available
66 	if (fBitmap) {
67 		fHeader.magic = B_TRANSLATOR_BITMAP;
68 		fHeader.bounds = fBitmap->Bounds();
69 		fHeader.rowBytes = fBitmap->BytesPerRow();
70 		fHeader.colors = fBitmap->ColorSpace();
71 		fHeader.dataSize = static_cast<uint32>
72 			((fHeader.bounds.Height() + 1) * fHeader.rowBytes);
73 		fSize = sizeof(TranslatorBitmap) + fHeader.dataSize;
74 
75 		if (B_HOST_IS_BENDIAN)
76 			memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap));
77 		else
78 			SwapHeader(&fHeader, fpBigEndianHeader);
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 (!fDetached)
100 		delete fBitmap;
101 	fBitmap = NULL;
102 
103 	delete fpBigEndianHeader;
104 	fpBigEndianHeader = NULL;
105 }
106 
107 // ---------------------------------------------------------------
108 // ReadAt
109 //
110 // Reads data from the stream at a specific position and for a
111 // specific amount. The first sizeof(TranslatorBitmap) bytes
112 // are the bitmap header. The header is always written out
113 // and read in as Big Endian byte order.
114 //
115 // Preconditions:
116 //
117 // Parameters: pos, the position in the stream to read from
118 //             buffer, where the data will be read into
119 //             size, the amount of data to read
120 //
121 // Postconditions:
122 //
123 // Returns: B_ERROR if there is no bitmap stored by the stream
124 //                  or if pos is a bad value,
125 //          B_BAD_VALUE if buffer is NULL or pos is invalid
126 //          or the amount read if the result >= 0
127 // ---------------------------------------------------------------
128 ssize_t
129 BBitmapStream::ReadAt(off_t pos, void *buffer, size_t size)
130 {
131 	if (!fBitmap)
132 		return B_ERROR;
133 	if (!size)
134 		return B_NO_ERROR;
135 	if (pos >= fSize)
136 		return B_ERROR;
137 	if (!buffer || pos < 0)
138 		return B_BAD_VALUE;
139 
140 	ssize_t toRead;
141 	void *source;
142 
143 	if (pos < sizeof(TranslatorBitmap)) {
144 		toRead = sizeof(TranslatorBitmap) - pos;
145 		source = (reinterpret_cast<uint8 *>(fpBigEndianHeader)) + pos;
146 	} else {
147 		toRead = fSize - pos;
148 		source = (reinterpret_cast<uint8 *>(fBitmap->Bits())) + pos -
149 			sizeof(TranslatorBitmap);
150 	}
151 	if (toRead > (ssize_t)size)
152 		toRead = (ssize_t)size;
153 
154 	memcpy(buffer, source, toRead);
155 	return toRead;
156 }
157 
158 // ---------------------------------------------------------------
159 // WriteAt
160 //
161 // Writes data to the bitmap from data, starting at position pos
162 // of size, size. The first sizeof(TranslatorBitmap) bytes
163 // of data must be the TranslatorBitmap header in the Big
164 // Endian byte order, otherwise, the data will fail to be
165 // successfully written.
166 //
167 // Preconditions:
168 //
169 // Parameters: pos, the position in the stream to write to
170 //             data, the data to write to the stream
171 //             size, the size of the data to write to the stream
172 //
173 // Postconditions:
174 //
175 // Returns: B_BAD_VALUE if size is bad or data is NULL or pos is invalid,
176 //          B_MISMATCHED_VALUES if the bitmap header is bad,
177 //			B_ERROR if error allocating memory or setting up
178 //			        big endian header,
179 //          or the amount written if the result is >= 0
180 // ---------------------------------------------------------------
181 ssize_t
182 BBitmapStream::WriteAt(off_t pos, const void *data, size_t size)
183 {
184 	if (!size)
185 		return B_NO_ERROR;
186 	if (!data || pos < 0 || pos > fSize)
187 		return B_BAD_VALUE;
188 
189 	ssize_t written = 0;
190 	while (size > 0) {
191 		size_t toWrite;
192 		void *dest;
193 		// We depend on writing the header separately in detecting
194 		// changes to it
195 		if (pos < sizeof(TranslatorBitmap)) {
196 			toWrite = sizeof(TranslatorBitmap) - pos;
197 			dest = (reinterpret_cast<uint8 *> (&fHeader)) + pos;
198 		} else {
199 			toWrite = fHeader.dataSize - pos + sizeof(TranslatorBitmap);
200 			dest = (reinterpret_cast<uint8 *> (fBitmap->Bits())) +
201 				pos - sizeof(TranslatorBitmap);
202 		}
203 		if (toWrite > size)
204 			toWrite = size;
205 		if (!toWrite && size)
206 			// i.e. we've been told to write too much
207 			return B_BAD_VALUE;
208 
209 		memcpy(dest, data, toWrite);
210 		pos += toWrite;
211 		written += toWrite;
212 		data = (reinterpret_cast<const uint8 *> (data)) + toWrite;
213 		size -= toWrite;
214 		if (pos > fSize)
215 			fSize = pos;
216 		// If we change the header, the rest needs to be reset
217 		if (pos == sizeof(TranslatorBitmap)) {
218 			// Setup both host and Big Endian byte order bitmap headers
219 			memcpy(fpBigEndianHeader, &fHeader, sizeof(TranslatorBitmap));
220 			if (B_HOST_IS_LENDIAN)
221 				SwapHeader(fpBigEndianHeader, &fHeader);
222 
223 			if (fBitmap
224 				&& (fBitmap->Bounds() != fHeader.bounds
225 					|| fBitmap->ColorSpace() != fHeader.colors
226 					|| (uint32)fBitmap->BytesPerRow() != fHeader.rowBytes)) {
227 				if (!fDetached)
228 					// if someone detached, we don't delete
229 					delete fBitmap;
230 				fBitmap = NULL;
231 			}
232 			if (!fBitmap) {
233 				if (fHeader.bounds.left > 0.0 || fHeader.bounds.top > 0.0)
234 					DEBUGGER("non-origin bounds!");
235 				fBitmap = new BBitmap(fHeader.bounds, fHeader.colors);
236 				if (!fBitmap)
237 					return B_ERROR;
238 				if ((uint32)fBitmap->BytesPerRow() != fHeader.rowBytes) {
239 					fprintf(stderr, "BitmapStream %ld %ld\n", fBitmap->BytesPerRow(), fHeader.rowBytes);
240 					return B_MISMATCHED_VALUES;
241 				}
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