xref: /haiku/src/kits/translation/BitmapStream.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
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 					return B_MISMATCHED_VALUES;
240 			}
241 			if (fBitmap)
242 				fSize = sizeof(TranslatorBitmap) + fBitmap->BitsLength();
243 		}
244 	}
245 	return written;
246 }
247 
248 // ---------------------------------------------------------------
249 // Seek
250 //
251 // Changes the current stream position.
252 //
253 // Preconditions:
254 //
255 // Parameters: position, the position offset
256 //             whence, decides how the position offset is used
257 //                     SEEK_CUR, position is added to current
258 //                               stream position
259 //                     SEEK_END, position is added to the end
260 //                               stream position
261 //                     SEEK_SET, the stream position is set to
262 //                               position
263 //
264 // Postconditions:
265 //
266 // Returns: B_BAD_VALUE if the position is bad
267 //          or the new position value if the result >= 0
268 // ---------------------------------------------------------------
269 off_t
270 BBitmapStream::Seek(off_t position, uint32 whence)
271 {
272 	// When whence == SEEK_SET, it just falls through to
273 	// fPosition = position
274 	if (whence == SEEK_CUR)
275 		position += fPosition;
276 	if (whence == SEEK_END)
277 		position += fSize;
278 
279 	if (position < 0)
280 		return B_BAD_VALUE;
281 	if (position > fSize)
282 		return B_BAD_VALUE;
283 
284 	fPosition = position;
285 	return fPosition;
286 }
287 
288 // ---------------------------------------------------------------
289 // Position
290 //
291 // Returns the current stream position
292 //
293 // Preconditions:
294 //
295 // Parameters:
296 //
297 // Postconditions:
298 //
299 // Returns: returns the curren stream position
300 // ---------------------------------------------------------------
301 off_t
302 BBitmapStream::Position() const
303 {
304 	return fPosition;
305 }
306 
307 
308 // ---------------------------------------------------------------
309 // Size
310 //
311 // Returns the curren stream size
312 //
313 // Preconditions:
314 //
315 // Parameters:
316 //
317 // Postconditions:
318 //
319 // Returns: returns the current stream size
320 // ---------------------------------------------------------------
321 off_t
322 BBitmapStream::Size() const
323 {
324 	return fSize;
325 }
326 
327 // ---------------------------------------------------------------
328 // SetSize
329 //
330 // Sets the size of the data, but I'm not sure if this function
331 // has any real purpose.
332 //
333 // Preconditions:
334 //
335 // Parameters: size, the size to set the stream size to.
336 //
337 // Postconditions:
338 //
339 // Returns: B_BAD_VALUE, if size is a bad value
340 //          B_NO_ERROR, if size is a valid value
341 // ---------------------------------------------------------------
342 status_t
343 BBitmapStream::SetSize(off_t size)
344 {
345 	if (size < 0)
346 		return B_BAD_VALUE;
347 	if (fBitmap && (size > fHeader.dataSize + sizeof(TranslatorBitmap)))
348 		return B_BAD_VALUE;
349 	//	Problem:
350 	//	What if someone calls SetSize() before writing the header,
351 	//  so we don't know what bitmap to create?
352 	//	Solution:
353 	//	We assume people will write the header before any data,
354 	//	so SetSize() is really not going to do anything.
355 	if (fBitmap)
356 		// if we checked that the size was OK
357 		fSize = size;
358 
359 	return B_NO_ERROR;
360 }
361 
362 // ---------------------------------------------------------------
363 // DetachBitmap
364 //
365 // Returns the internal bitmap through outBitmap so the user
366 // can do whatever they want to it. It means that when the
367 // BBitmapStream is deleted, the bitmap is not deleted. After
368 // the bitmap has been detached, it is still used by the stream,
369 // but it is never deleted by the stream.
370 //
371 // Preconditions:
372 //
373 // Parameters: outBitmap, where the bitmap is detached to
374 //
375 // Postconditions:
376 //
377 // Returns: B_BAD_VALUE, if outBitmap is NULL
378 //          B_ERROR,     if the bitmap is NULL or
379 //                       has already been detached
380 //          B_NO_ERROR,  if the bitmap was successfully detached
381 // ---------------------------------------------------------------
382 status_t
383 BBitmapStream::DetachBitmap(BBitmap **outBitmap)
384 {
385 	if (!outBitmap)
386 		return B_BAD_VALUE;
387 	if (!fBitmap || fDetached) {
388 		*outBitmap = NULL;
389 		return B_ERROR;
390 	}
391 
392 	fDetached = true;
393 	*outBitmap = fBitmap;
394 
395 	return B_NO_ERROR;
396 }
397 
398 // ---------------------------------------------------------------
399 // SwapHeader
400 //
401 // Swaps the byte order of source, no matter what the
402 // byte order, and copies the result to destination
403 //
404 // Preconditions: both parameters must not be null
405 //
406 // Parameters:	source,			data to be swapped
407 //
408 //				destination,	where the swapped data will
409 //								be copied to
410 //
411 // Postconditions:
412 //
413 // Returns:
414 //
415 // ---------------------------------------------------------------
416 void
417 BBitmapStream::SwapHeader(const TranslatorBitmap *source,
418 	TranslatorBitmap *destination)
419 {
420 	memcpy(destination, source, sizeof(TranslatorBitmap));
421 	swap_data(B_UINT32_TYPE, destination, sizeof(TranslatorBitmap),
422 		B_SWAP_ALWAYS);
423 }
424 
425 // ---------------------------------------------------------------
426 // _ReservedBitmapStream1()
427 //
428 // It doesn't do anything :). Its here only for past/future
429 // binary compatibility.
430 //
431 // Preconditions:
432 //
433 // Parameters:
434 //
435 // Postconditions:
436 //
437 // Returns:
438 // ---------------------------------------------------------------
439 void
440 BBitmapStream::_ReservedBitmapStream1()
441 {
442 }
443 
444 // ---------------------------------------------------------------
445 // _ReservedBitmapStream2()
446 //
447 // It doesn't do anything :). Its only here for past/future
448 // binary compatibility.
449 //
450 // Preconditions:
451 //
452 // Parameters:
453 //
454 // Postconditions:
455 //
456 // Returns:
457 // ---------------------------------------------------------------
458 void
459 BBitmapStream::_ReservedBitmapStream2()
460 {
461 }
462 
463