xref: /haiku/src/add-ons/translators/bmp/BMPTranslator.cpp (revision f775a1fea73af07d29d619e6258af43bf1f7746d)
1 /*
2  * Copyright 2002-2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Wilber <mwilber@users.berlios.de>
7  */
8 
9 #include "BMPTranslator.h"
10 
11 #include <new>
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include "BMPView.h"
16 
17 using std::nothrow;
18 
19 //#define INFO(x) printf(x);
20 #define INFO(x)
21 //#define ERROR(x) printf(x);
22 #define ERROR(x)
23 
24 // The input formats that this translator supports.
25 translation_format gInputFormats[] = {
26 	{
27 		B_TRANSLATOR_BITMAP,
28 		B_TRANSLATOR_BITMAP,
29 		BBT_IN_QUALITY,
30 		BBT_IN_CAPABILITY,
31 		"image/x-be-bitmap",
32 		"Be Bitmap Format (BMPTranslator)"
33 	},
34 	{
35 		B_BMP_FORMAT,
36 		B_TRANSLATOR_BITMAP,
37 		BMP_IN_QUALITY,
38 		BMP_IN_CAPABILITY,
39 		"image/x-bmp",
40 		"BMP image"
41 	}
42 };
43 
44 // The output formats that this translator supports.
45 translation_format gOutputFormats[] = {
46 	{
47 		B_TRANSLATOR_BITMAP,
48 		B_TRANSLATOR_BITMAP,
49 		BBT_OUT_QUALITY,
50 		BBT_OUT_CAPABILITY,
51 		"image/x-be-bitmap",
52 		"Be Bitmap Format (BMPTranslator)"
53 	},
54 	{
55 		B_BMP_FORMAT,
56 		B_TRANSLATOR_BITMAP,
57 		BMP_OUT_QUALITY,
58 		BMP_OUT_CAPABILITY,
59 		"image/x-bmp",
60 		"BMP image"
61 	}
62 };
63 
64 // Default settings for the Translator
65 TranSetting gDefaultSettings[] = {
66 	{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
67 	{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}
68 };
69 
70 // ---------------------------------------------------------------
71 // make_nth_translator
72 //
73 // Creates a BMPTranslator object to be used by BTranslatorRoster
74 //
75 // Preconditions:
76 //
77 // Parameters: n,		The translator to return. Since
78 //						BMPTranslator only publishes one
79 //						translator, it only returns a
80 //						BMPTranslator if n == 0
81 //
82 //             you, 	The image_id of the add-on that
83 //						contains code (not used).
84 //
85 //             flags,	Has no meaning yet, should be 0.
86 //
87 // Postconditions:
88 //
89 // Returns: NULL if n is not zero,
90 //          a new BMPTranslator if n is zero
91 // ---------------------------------------------------------------
92 BTranslator *
93 make_nth_translator(int32 n, image_id you, uint32 flags, ...)
94 {
95 	if (!n)
96 		return new BMPTranslator();
97 	else
98 		return NULL;
99 }
100 
101 // ---------------------------------------------------------------
102 // Constructor
103 //
104 // Sets up the version info and the name of the translator so that
105 // these values can be returned when they are requested.
106 //
107 // Preconditions:
108 //
109 // Parameters:
110 //
111 // Postconditions:
112 //
113 // Returns:
114 // ---------------------------------------------------------------
115 BMPTranslator::BMPTranslator()
116 	: BaseTranslator("BMP Images", "BMP image translator",
117 		BMP_TRANSLATOR_VERSION,
118 		gInputFormats, sizeof(gInputFormats) / sizeof(translation_format),
119 		gOutputFormats, sizeof(gOutputFormats) / sizeof(translation_format),
120 		"BMPTranslator_Settings",
121 		gDefaultSettings, sizeof(gDefaultSettings) / sizeof(TranSetting),
122 		B_TRANSLATOR_BITMAP, B_BMP_FORMAT)
123 {
124 }
125 
126 // ---------------------------------------------------------------
127 // Destructor
128 //
129 // Does nothing
130 //
131 // Preconditions:
132 //
133 // Parameters:
134 //
135 // Postconditions:
136 //
137 // Returns:
138 // ---------------------------------------------------------------
139 BMPTranslator::~BMPTranslator()
140 {
141 }
142 
143 // ---------------------------------------------------------------
144 // get_padding
145 //
146 // Returns number of bytes of padding required at the end of
147 // the row by the BMP format
148 //
149 //
150 // Preconditions: If bitsperpixel is zero, a division by zero
151 //                will occur, which is bad
152 //
153 // Parameters:	width, width of the row, in pixels
154 //
155 //				bitsperpixel, bitdepth of the image
156 //
157 // Postconditions:
158 //
159 // Returns:
160 // ---------------------------------------------------------------
161 int32
162 get_padding(uint32 width, uint16 bitsperpixel)
163 {
164 	int32 padding = 0;
165 
166 	if (bitsperpixel > 8) {
167 		uint8 bytesPerPixel = bitsperpixel / 8;
168 		padding = (width * bytesPerPixel) % 4;
169 	} else {
170 		uint8 pixelsPerByte = 8 / bitsperpixel;
171 		if (!(width % pixelsPerByte))
172 			padding = (width / pixelsPerByte) % 4;
173 		else
174 			padding = ((width + pixelsPerByte -
175 				(width % pixelsPerByte)) /
176 					pixelsPerByte) % 4;
177 	}
178 
179 	if (padding)
180 		padding = 4 - padding;
181 
182 	return padding;
183 }
184 
185 // ---------------------------------------------------------------
186 // get_rowbytes
187 //
188 // Returns number of bytes required to store a row of BMP pixels
189 // with a width of width and a bit depth of bitsperpixel.
190 //
191 //
192 // Preconditions: If bitsperpixel is zero, a division by zero
193 //                will occur, which is bad
194 //
195 // Parameters:	width, width of the row, in pixels
196 //
197 //				bitsperpixel, bitdepth of the image
198 //
199 // Postconditions:
200 //
201 // Returns:
202 // ---------------------------------------------------------------
203 int32
204 get_rowbytes(uint32 width, uint16 bitsperpixel)
205 {
206 	int32 rowbytes = 0;
207 	int32 padding = get_padding(width, bitsperpixel);
208 
209 	if (bitsperpixel > 8) {
210 		uint8 bytesPerPixel = bitsperpixel / 8;
211 		rowbytes = (width * bytesPerPixel) + padding;
212 	} else {
213 		uint8 pixelsPerByte = 8 / bitsperpixel;
214 		rowbytes = (width / pixelsPerByte) +
215 			((width % pixelsPerByte) ? 1 : 0) + padding;
216 	}
217 
218 	return rowbytes;
219 }
220 
221 // ---------------------------------------------------------------
222 // identify_bmp_header
223 //
224 // Determines if the data in inSource is in the MS or OS/2 BMP
225 // format. If it is, it returns info about the data in inSource
226 // to outInfo, pfileheader, pmsheader, pfrommsformat and os2skip.
227 //
228 // Preconditions:
229 //
230 // Parameters:	inSource,	The source of the image data
231 //
232 //				outInfo,	Information about the translator
233 //							is copied here
234 //
235 //				amtread,	Amount of data read from inSource
236 //							before this function was called
237 //
238 //				read,		Pointer to the data that was read
239 // 							in before this function was called
240 //
241 //				pfileheader,	File header info for the BMP is
242 //								copied here after it is read from
243 //								the file.
244 //
245 //				pmsheader,		BMP header info read in from the
246 //								BMP file
247 //
248 //				pfrommsformat,	Set to true if BMP data is BMP
249 //								format, false if BMP data is OS/2
250 //								format.
251 //
252 //				pos2skip,	If data is in OS/2 format, the number
253 //							of bytes to skip between the header
254 //							data and image data is stored here
255 //
256 // Postconditions:
257 //
258 // Returns: B_NO_TRANSLATOR,	if the data does not look like
259 //								BMP format data
260 //
261 // B_ERROR,	if the header data could not be converted to host
262 //			format
263 //
264 // B_OK,	if the data looks like bits data and no errors were
265 //			encountered
266 // ---------------------------------------------------------------
267 status_t
268 identify_bmp_header(BPositionIO *inSource, translator_info *outInfo,
269 	BMPFileHeader *pfileheader = NULL, MSInfoHeader *pmsheader = NULL,
270 	bool *pfrommsformat = NULL, off_t *pos2skip = NULL)
271 {
272 	// read in the fileHeader
273 	uint8 buf[40];
274 	BMPFileHeader fileHeader;
275 	ssize_t size = 14;
276 	if (inSource->Read(buf, size) != size)
277 		return B_NO_TRANSLATOR;
278 
279 	// check BMP magic number
280 	const uint16 kBmpMagic = B_HOST_TO_LENDIAN_INT16('MB');
281 	uint16 sourceMagic;
282 	memcpy(&sourceMagic, buf, sizeof(uint16));
283 	if (sourceMagic != kBmpMagic)
284 		return B_NO_TRANSLATOR;
285 
286 	// convert fileHeader to host byte order
287 	memcpy(&fileHeader.magic, buf, 2);
288 	memcpy(&fileHeader.fileSize, buf + 2, 4);
289 	memcpy(&fileHeader.reserved, buf + 6, 4);
290 	memcpy(&fileHeader.dataOffset, buf + 10, 4);
291 	if (swap_data(B_UINT16_TYPE, &fileHeader.magic, sizeof(uint16),
292 		B_SWAP_LENDIAN_TO_HOST) != B_OK)
293 		return B_ERROR;
294 	if (swap_data(B_UINT32_TYPE,
295 		(reinterpret_cast<uint8 *> (&fileHeader)) + 2, 12,
296 		B_SWAP_LENDIAN_TO_HOST) != B_OK)
297 		return B_ERROR;
298 
299 	if (fileHeader.reserved != 0)
300 		return B_NO_TRANSLATOR;
301 
302 	uint32 headersize = 0;
303 	if (inSource->Read(&headersize, 4) != 4)
304 		return B_NO_TRANSLATOR;
305 	if (swap_data(B_UINT32_TYPE, &headersize, 4,
306 		B_SWAP_LENDIAN_TO_HOST) != B_OK)
307 		return B_ERROR;
308 
309 	if (headersize == sizeof(MSInfoHeader)) {
310 		// MS format
311 
312 		if (fileHeader.dataOffset < 54)
313 			return B_NO_TRANSLATOR;
314 
315 		MSInfoHeader msheader;
316 		msheader.size = headersize;
317 		if (inSource->Read(
318 			reinterpret_cast<uint8 *> (&msheader) + 4, 36) != 36)
319 			return B_NO_TRANSLATOR;
320 
321 		// convert msheader to host byte order
322 		if (swap_data(B_UINT32_TYPE,
323 			reinterpret_cast<uint8 *> (&msheader) + 4, 36,
324 			B_SWAP_LENDIAN_TO_HOST) != B_OK)
325 			return B_ERROR;
326 
327 		// check if msheader is valid
328 		if (msheader.width == 0 || msheader.height == 0)
329 			return B_NO_TRANSLATOR;
330 		if (msheader.planes != 1)
331 			return B_NO_TRANSLATOR;
332 		if ((msheader.bitsperpixel != 1 ||
333 				msheader.compression != BMP_NO_COMPRESS) &&
334 			(msheader.bitsperpixel != 4 ||
335 				msheader.compression != BMP_NO_COMPRESS) &&
336 			(msheader.bitsperpixel != 4 ||
337 				msheader.compression != BMP_RLE4_COMPRESS) &&
338 			(msheader.bitsperpixel != 8 ||
339 				msheader.compression != BMP_NO_COMPRESS) &&
340 			(msheader.bitsperpixel != 8 ||
341 				msheader.compression != BMP_RLE8_COMPRESS) &&
342 			(msheader.bitsperpixel != 24 ||
343 				msheader.compression != BMP_NO_COMPRESS) &&
344 			(msheader.bitsperpixel != 32 ||
345 				msheader.compression != BMP_NO_COMPRESS))
346 			return B_NO_TRANSLATOR;
347 		if (!msheader.imagesize && msheader.compression)
348 			return B_NO_TRANSLATOR;
349 		if (msheader.colorsimportant > msheader.colorsused)
350 			return B_NO_TRANSLATOR;
351 
352 		if (outInfo) {
353 			outInfo->type = B_BMP_FORMAT;
354 			outInfo->group = B_TRANSLATOR_BITMAP;
355 			outInfo->quality = BMP_IN_QUALITY;
356 			outInfo->capability = BMP_IN_CAPABILITY;
357 			sprintf(outInfo->name, "BMP image (MS format, %d bits",
358 				msheader.bitsperpixel);
359 			if (msheader.compression)
360 				strcat(outInfo->name, ", RLE)");
361 			else
362 				strcat(outInfo->name, ")");
363 			strcpy(outInfo->MIME, "image/x-bmp");
364 		}
365 
366 		if (pfileheader) {
367 			pfileheader->magic = fileHeader.magic;
368 			pfileheader->fileSize = fileHeader.fileSize;
369 			pfileheader->reserved = fileHeader.reserved;
370 			pfileheader->dataOffset = fileHeader.dataOffset;
371 		}
372 		if (pmsheader) {
373 			pmsheader->size = msheader.size;
374 			pmsheader->width = msheader.width;
375 			pmsheader->height = abs((int32)msheader.height);
376 				// TODO: negative height means the BMP is up side down
377 				// -> support this...
378 			pmsheader->planes = msheader.planes;
379 			pmsheader->bitsperpixel = msheader.bitsperpixel;
380 			pmsheader->compression = msheader.compression;
381 			pmsheader->imagesize = msheader.imagesize;
382 			pmsheader->xpixperm = msheader.xpixperm;
383 			pmsheader->ypixperm = msheader.ypixperm;
384 			pmsheader->colorsused = msheader.colorsused;
385 			pmsheader->colorsimportant = msheader.colorsimportant;
386 		}
387 		if (pfrommsformat)
388 			(*pfrommsformat) = true;
389 
390 		return B_OK;
391 
392 	} else if (headersize == sizeof(OS2InfoHeader)) {
393 		// OS/2 format
394 
395 		if (fileHeader.dataOffset < 26)
396 			return B_NO_TRANSLATOR;
397 
398 		OS2InfoHeader os2header;
399 		os2header.size = headersize;
400 		if (inSource->Read(
401 			reinterpret_cast<uint8 *> (&os2header) + 4, 8) != 8)
402 			return B_NO_TRANSLATOR;
403 
404 		// convert msheader to host byte order
405 		if (swap_data(B_UINT32_TYPE,
406 			reinterpret_cast<uint8 *> (&os2header) + 4, 8,
407 			B_SWAP_LENDIAN_TO_HOST) != B_OK)
408 			return B_ERROR;
409 
410 		// check if msheader is valid
411 		if (os2header.width == 0 || os2header.height == 0)
412 			return B_NO_TRANSLATOR;
413 		if (os2header.planes != 1)
414 			return B_NO_TRANSLATOR;
415 		if (os2header.bitsperpixel != 1 &&
416 			os2header.bitsperpixel != 4 &&
417 			os2header.bitsperpixel != 8 &&
418 			os2header.bitsperpixel != 24)
419 			return B_NO_TRANSLATOR;
420 
421 		if (outInfo) {
422 			outInfo->type = B_BMP_FORMAT;
423 			outInfo->group = B_TRANSLATOR_BITMAP;
424 			outInfo->quality = BMP_IN_QUALITY;
425 			outInfo->capability = BMP_IN_CAPABILITY;
426 			sprintf(outInfo->name, "BMP image (OS/2 format, %d bits)",
427 				os2header.bitsperpixel);
428 			strcpy(outInfo->MIME, "image/x-bmp");
429 		}
430 		if (pfileheader && pmsheader) {
431 			pfileheader->magic = 'MB';
432 			pfileheader->fileSize = 0;
433 			pfileheader->reserved = 0;
434 			pfileheader->dataOffset = 0;
435 
436 			pmsheader->size = 40;
437 			pmsheader->width = os2header.width;
438 			pmsheader->height = os2header.height;
439 			pmsheader->planes = 1;
440 			pmsheader->bitsperpixel = os2header.bitsperpixel;
441 			pmsheader->compression = BMP_NO_COMPRESS;
442 			pmsheader->imagesize = 0;
443 			pmsheader->xpixperm = 2835; // 72 dpi horizontal
444 			pmsheader->ypixperm = 2835; // 72 dpi vertical
445 			pmsheader->colorsused = 0;
446 			pmsheader->colorsimportant = 0;
447 
448 			// determine fileSize / imagesize
449 			switch (pmsheader->bitsperpixel) {
450 				case 24:
451 					if (pos2skip && fileHeader.dataOffset > 26)
452 						(*pos2skip) = fileHeader.dataOffset - 26;
453 
454 					pfileheader->dataOffset = 54;
455 					pmsheader->imagesize = get_rowbytes(pmsheader->width,
456 						pmsheader->bitsperpixel) * pmsheader->height;
457 					pfileheader->fileSize = pfileheader->dataOffset +
458 						pmsheader->imagesize;
459 
460 					break;
461 
462 				case 8:
463 				case 4:
464 				case 1:
465 				{
466 					uint16 ncolors = 1 << pmsheader->bitsperpixel;
467 					pmsheader->colorsused = ncolors;
468 					pmsheader->colorsimportant = ncolors;
469 					if (pos2skip && fileHeader.dataOffset >
470 						static_cast<uint32> (26 + (ncolors * 3)))
471 							(*pos2skip) = fileHeader.dataOffset -
472 								(26 + (ncolors * 3));
473 
474 					pfileheader->dataOffset = 54 + (ncolors * 4);
475 					pmsheader->imagesize = get_rowbytes(pmsheader->width,
476 						pmsheader->bitsperpixel) * pmsheader->height;
477 					pfileheader->fileSize = pfileheader->dataOffset +
478 						pmsheader->imagesize;
479 
480 					break;
481 				}
482 
483 				default:
484 					break;
485 			}
486 		}
487 		if (pfrommsformat)
488 			(*pfrommsformat) = false;
489 
490 		return B_OK;
491 
492 	} else
493 		return B_NO_TRANSLATOR;
494 }
495 
496 // ---------------------------------------------------------------
497 // DerivedIdentify
498 //
499 // Examines the data from inSource and determines if it is in a
500 // format that this translator knows how to work with.
501 //
502 // Preconditions:
503 //
504 // Parameters:	inSource,	where the data to examine is
505 //
506 //				inFormat,	a hint about the data in inSource,
507 //							it is ignored since it is only a hint
508 //
509 //				ioExtension,	configuration settings for the
510 //								translator
511 //
512 //				outInfo,	information about what data is in
513 //							inSource and how well this translator
514 //							can handle that data is stored here
515 //
516 //				outType,	The format that the user wants
517 //							the data in inSource to be
518 //							converted to
519 //
520 // Postconditions:
521 //
522 // Returns: B_NO_TRANSLATOR,	if this translator can't handle
523 //								the data in inSource
524 //
525 // B_ERROR,	if there was an error converting the data to the host
526 //			format
527 //
528 // B_BAD_VALUE, if the settings in ioExtension are bad
529 //
530 // B_OK,	if this translator understand the data and there were
531 //			no errors found
532 // ---------------------------------------------------------------
533 status_t
534 BMPTranslator::DerivedIdentify(BPositionIO *inSource,
535 	const translation_format *inFormat, BMessage *ioExtension,
536 	translator_info *outInfo, uint32 outType)
537 {
538 	return identify_bmp_header(inSource, outInfo);
539 }
540 
541 // ---------------------------------------------------------------
542 // translate_from_bits_to_bmp24
543 //
544 // Converts various varieties of the Be Bitmap format ('bits') to
545 // the MS BMP 24-bit format.
546 //
547 // Preconditions:
548 //
549 // Parameters:	inSource,	contains the bits data to convert
550 //
551 //				outDestination,	where the BMP data will be written
552 //
553 //				fromspace,	the format of the data in inSource
554 //
555 //				msheader,	contains information about the BMP
556 //							dimensions and filesize
557 //
558 // Postconditions:
559 //
560 // Returns: B_ERROR,	if memory couldn't be allocated or another
561 //						error occured
562 //
563 // B_OK,	if no errors occurred
564 // ---------------------------------------------------------------
565 status_t
566 translate_from_bits_to_bmp24(BPositionIO *inSource,
567 BPositionIO *outDestination, color_space fromspace, MSInfoHeader &msheader)
568 {
569 	// TODO: WHOHA! big switch statement for the innermost loop!
570 	// make a loop per colorspace and put the switch outside!!!
571 	// remove memcpy() to copy 3 bytes
572 	int32 bitsBytesPerPixel = 0;
573 	switch (fromspace) {
574 		case B_RGB32:
575 		case B_RGB32_BIG:
576 		case B_RGBA32:
577 		case B_RGBA32_BIG:
578 		case B_CMY32:
579 		case B_CMYA32:
580 		case B_CMYK32:
581 			bitsBytesPerPixel = 4;
582 			break;
583 
584 		case B_RGB24:
585 		case B_RGB24_BIG:
586 		case B_CMY24:
587 			bitsBytesPerPixel = 3;
588 			break;
589 
590 		case B_RGB16:
591 		case B_RGB16_BIG:
592 		case B_RGBA15:
593 		case B_RGBA15_BIG:
594 		case B_RGB15:
595 		case B_RGB15_BIG:
596 			bitsBytesPerPixel = 2;
597 			break;
598 
599 		case B_CMAP8:
600 		case B_GRAY8:
601 			bitsBytesPerPixel = 1;
602 			break;
603 
604 		default:
605 			return B_ERROR;
606 	}
607 	int32 bitsRowBytes = msheader.width * bitsBytesPerPixel;
608 	int32 padding = get_padding(msheader.width, msheader.bitsperpixel);
609 	int32 bmpRowBytes =
610 		get_rowbytes(msheader.width, msheader.bitsperpixel);
611 	uint32 bmppixrow = 0;
612 	off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes);
613 	inSource->Seek(bitsoffset, SEEK_CUR);
614 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
615 	if (!bmpRowData)
616 		return B_NO_MEMORY;
617 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
618 	if (!bitsRowData) {
619 		delete[] bmpRowData;
620 		return B_NO_MEMORY;
621 	}
622 	memset(bmpRowData + (bmpRowBytes - padding), 0, padding);
623 	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
624 	const color_map *pmap = NULL;
625 	if (fromspace == B_CMAP8) {
626 		pmap = system_colors();
627 		if (!pmap)
628 			return B_ERROR;
629 	}
630 	while (rd == static_cast<ssize_t>(bitsRowBytes)) {
631 
632 		for (uint32 i = 0; i < msheader.width; i++) {
633 			uint8 *bitspixel, *bmppixel;
634 			uint16 val;
635 			switch (fromspace) {
636 				case B_RGB32:
637 				case B_RGBA32:
638 				case B_RGB24:
639 					memcpy(bmpRowData + (i * 3),
640 						bitsRowData + (i * bitsBytesPerPixel), 3);
641 					break;
642 
643 				case B_RGB16:
644 				case B_RGB16_BIG:
645 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
646 					bmppixel = bmpRowData + (i * 3);
647 					if (fromspace == B_RGB16)
648 						val = bitspixel[0] + (bitspixel[1] << 8);
649 					else
650 						val = bitspixel[1] + (bitspixel[0] << 8);
651 					bmppixel[0] =
652 						((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
653 					bmppixel[1] =
654 						((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9);
655 					bmppixel[2] =
656 						((val & 0xf800) >> 8) | ((val & 0xf800) >> 13);
657 					break;
658 
659 				case B_RGB15:
660 				case B_RGB15_BIG:
661 				case B_RGBA15:
662 				case B_RGBA15_BIG:
663 					// NOTE: the alpha data for B_RGBA15* is not used
664 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
665 					bmppixel = bmpRowData + (i * 3);
666 					if (fromspace == B_RGB15 || fromspace == B_RGBA15)
667 						val = bitspixel[0] + (bitspixel[1] << 8);
668 					else
669 						val = bitspixel[1] + (bitspixel[0] << 8);
670 					bmppixel[0] =
671 						((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
672 					bmppixel[1] =
673 						((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
674 					bmppixel[2] =
675 						((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
676 					break;
677 
678 				case B_RGB32_BIG:
679 				case B_RGBA32_BIG:
680 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
681 					bmppixel = bmpRowData + (i * 3);
682 					bmppixel[0] = bitspixel[3];
683 					bmppixel[1] = bitspixel[2];
684 					bmppixel[2] = bitspixel[1];
685 					break;
686 
687 				case B_RGB24_BIG:
688 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
689 					bmppixel = bmpRowData + (i * 3);
690 					bmppixel[0] = bitspixel[2];
691 					bmppixel[1] = bitspixel[1];
692 					bmppixel[2] = bitspixel[0];
693 					break;
694 
695 				case B_CMAP8:
696 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
697 					bmppixel = bmpRowData + (i * 3);
698 					rgb_color c = pmap->color_list[bitspixel[0]];
699 					bmppixel[0] = c.blue;
700 					bmppixel[1] = c.green;
701 					bmppixel[2] = c.red;
702 					break;
703 
704 				case B_GRAY8:
705 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
706 					bmppixel = bmpRowData + (i * 3);
707 					bmppixel[0] = bitspixel[0];
708 					bmppixel[1] = bitspixel[0];
709 					bmppixel[2] = bitspixel[0];
710 					break;
711 
712 				case B_CMYK32:
713 				{
714 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
715 					bmppixel = bmpRowData + (i * 3);
716 
717 					int32 comp = 255 - bitspixel[2] - bitspixel[3];
718 					bmppixel[0] = (comp < 0) ? 0 : comp;
719 
720 					comp = 255 - bitspixel[1] - bitspixel[3];
721 					bmppixel[1] = (comp < 0) ? 0 : comp;
722 
723 					comp = 255 - bitspixel[0] - bitspixel[3];
724 					bmppixel[2] = (comp < 0) ? 0 : comp;
725 					break;
726 				}
727 
728 				case B_CMY32:
729 				case B_CMYA32:
730 				case B_CMY24:
731 					bitspixel = bitsRowData + (i * bitsBytesPerPixel);
732 					bmppixel = bmpRowData + (i * 3);
733 					bmppixel[0] = 255 - bitspixel[2];
734 					bmppixel[1] = 255 - bitspixel[1];
735 					bmppixel[2] = 255 - bitspixel[0];
736 					break;
737 
738 				default:
739 					break;
740 			} // switch (fromspace)
741 		} // for for (uint32 i = 0; i < msheader.width; i++)
742 
743 		outDestination->Write(bmpRowData, bmpRowBytes);
744 		bmppixrow++;
745 		// if I've read all of the pixel data, break
746 		// out of the loop so I don't try to read
747 		// non-pixel data
748 		if (bmppixrow == msheader.height)
749 			break;
750 
751 		inSource->Seek(bitsRowBytes * -2, SEEK_CUR);
752 		rd = inSource->Read(bitsRowData, bitsRowBytes);
753 	} // while (rd == bitsRowBytes)
754 
755 	delete[] bmpRowData;
756 	delete[] bitsRowData;
757 
758 	return B_OK;
759 }
760 
761 // ---------------------------------------------------------------
762 // translate_from_bits8_to_bmp8
763 //
764 // Converts 8-bit Be Bitmaps ('bits') to the MS 8-bit BMP format
765 //
766 // Preconditions:
767 //
768 // Parameters:	inSource,	contains the bits data to convert
769 //
770 //				outDestination,	where the BMP data will be written
771 //
772 //				bitsRowBytes,	number of bytes in one row of
773 //								bits data
774 //
775 //				msheader,	contains information about the BMP
776 //							dimensions and filesize
777 //
778 // Postconditions:
779 //
780 // Returns: B_ERROR,	if memory couldn't be allocated or another
781 //						error occured
782 //
783 // B_OK,	if no errors occurred
784 // ---------------------------------------------------------------
785 status_t
786 translate_from_bits8_to_bmp8(BPositionIO *inSource,
787 	BPositionIO *outDestination, int32 bitsRowBytes, MSInfoHeader &msheader)
788 {
789 	int32 padding = get_padding(msheader.width, msheader.bitsperpixel);
790 	int32 bmpRowBytes =
791 		get_rowbytes(msheader.width, msheader.bitsperpixel);
792 	uint32 bmppixrow = 0;
793 	off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes);
794 	inSource->Seek(bitsoffset, SEEK_CUR);
795 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
796 	if (!bmpRowData)
797 		return B_NO_MEMORY;
798 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
799 	if (!bitsRowData) {
800 		delete[] bmpRowData;
801 		return B_NO_MEMORY;
802 	}
803 	memset(bmpRowData + (bmpRowBytes - padding), 0, padding);
804 	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
805 	while (rd == bitsRowBytes) {
806 		memcpy(bmpRowData, bitsRowData, msheader.width);
807 		outDestination->Write(bmpRowData, bmpRowBytes);
808 		bmppixrow++;
809 		// if I've read all of the pixel data, break
810 		// out of the loop so I don't try to read
811 		// non-pixel data
812 		if (bmppixrow == msheader.height)
813 			break;
814 
815 		inSource->Seek(bitsRowBytes * -2, SEEK_CUR);
816 		rd = inSource->Read(bitsRowData, bitsRowBytes);
817 	} // while (rd == bitsRowBytes)
818 
819 	delete[] bmpRowData;
820 	delete[] bitsRowData;
821 
822 	return B_OK;
823 }
824 
825 // ---------------------------------------------------------------
826 // translate_from_bits1_to_bmp1
827 //
828 // Converts 1-bit Be Bitmaps ('bits') to the MS 1-bit BMP format
829 //
830 // Preconditions:
831 //
832 // Parameters:	inSource,	contains the bits data to convert
833 //
834 //				outDestination,	where the BMP data will be written
835 //
836 //				bitsRowBytes,	number of bytes in one row of
837 //								bits data
838 //
839 //				msheader,	contains information about the BMP
840 //							dimensions and filesize
841 //
842 // Postconditions:
843 //
844 // Returns: B_ERROR,	if memory couldn't be allocated or another
845 //						error occured
846 //
847 // B_OK,	if no errors occurred
848 // ---------------------------------------------------------------
849 status_t
850 translate_from_bits1_to_bmp1(BPositionIO *inSource,
851 	BPositionIO *outDestination, int32 bitsRowBytes, MSInfoHeader &msheader)
852 {
853 	uint8 pixelsPerByte = 8 / msheader.bitsperpixel;
854 	int32 bmpRowBytes =
855 		get_rowbytes(msheader.width, msheader.bitsperpixel);
856 	uint32 bmppixrow = 0;
857 	off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes);
858 	inSource->Seek(bitsoffset, SEEK_CUR);
859 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
860 	if (!bmpRowData)
861 		return B_NO_MEMORY;
862 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
863 	if (!bitsRowData) {
864 		delete[] bmpRowData;
865 		return B_NO_MEMORY;
866 	}
867 	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
868 	while (rd == bitsRowBytes) {
869 		uint32 bmppixcol = 0;
870 		memset(bmpRowData, 0, bmpRowBytes);
871 		for (int32 i = 0; (bmppixcol < msheader.width) &&
872 			(i < bitsRowBytes); i++) {
873 			// process each byte in the row
874 			uint8 pixels = bitsRowData[i];
875 			for (uint8 compbit = 128; (bmppixcol < msheader.width) &&
876 				compbit; compbit >>= 1) {
877 				// for each bit in the current byte, convert to a BMP palette
878 				// index and store that in the bmpRowData
879 				uint8 index;
880 				if (pixels & compbit)
881 					// 1 == black
882 					index = 1;
883 				else
884 					// 0 == white
885 					index = 0;
886 				bmpRowData[bmppixcol / pixelsPerByte] |=
887 					index << (7 - (bmppixcol % pixelsPerByte));
888 				bmppixcol++;
889 			}
890 		}
891 
892 		outDestination->Write(bmpRowData, bmpRowBytes);
893 		bmppixrow++;
894 		// if I've read all of the pixel data, break
895 		// out of the loop so I don't try to read
896 		// non-pixel data
897 		if (bmppixrow == msheader.height)
898 			break;
899 
900 		inSource->Seek(bitsRowBytes * -2, SEEK_CUR);
901 		rd = inSource->Read(bitsRowData, bitsRowBytes);
902 	} // while (rd == bitsRowBytes)
903 
904 	delete[] bmpRowData;
905 	delete[] bitsRowData;
906 
907 	return B_OK;
908 }
909 
910 // ---------------------------------------------------------------
911 // write_bmp_headers
912 //
913 // Writes the MS BMP headers (fileHeader and msheader)
914 // to outDestination.
915 //
916 // Preconditions:
917 //
918 // Parameters:	outDestination,	where the headers are written to
919 //
920 // 				fileHeader, BMP file header data
921 //
922 //				msheader, BMP info header data
923 //
924 // Postconditions:
925 //
926 // Returns: B_ERROR, if something went wrong
927 //
928 // B_OK, if there were no problems writing out the headers
929 // ---------------------------------------------------------------
930 status_t
931 write_bmp_headers(BPositionIO *outDestination, BMPFileHeader &fileHeader,
932 	MSInfoHeader &msheader)
933 {
934 	uint8 bmpheaders[54];
935 	memcpy(bmpheaders, &fileHeader.magic, sizeof(uint16));
936 	memcpy(bmpheaders + 2, &fileHeader.fileSize, sizeof(uint32));
937 	memcpy(bmpheaders + 6, &fileHeader.reserved, sizeof(uint32));
938 	memcpy(bmpheaders + 10, &fileHeader.dataOffset, sizeof(uint32));
939 	memcpy(bmpheaders + 14, &msheader, sizeof(msheader));
940 	if (swap_data(B_UINT16_TYPE, bmpheaders, 2,
941 		B_SWAP_HOST_TO_LENDIAN) != B_OK)
942 		return B_ERROR;
943 	if (swap_data(B_UINT32_TYPE, bmpheaders + 2, 12,
944 		B_SWAP_HOST_TO_LENDIAN) != B_OK)
945 		return B_ERROR;
946 	if (swap_data(B_UINT32_TYPE, bmpheaders + 14,
947 		sizeof(MSInfoHeader), B_SWAP_HOST_TO_LENDIAN) != B_OK)
948 		return B_ERROR;
949 	if (outDestination->Write(bmpheaders, 54) != 54)
950 		return B_ERROR;
951 
952 	return B_OK;
953 }
954 
955 // ---------------------------------------------------------------
956 // translate_from_bits
957 //
958 // Convert the data in inSource from the Be Bitmap format ('bits')
959 // to the format specified in outType (either bits or BMP).
960 //
961 // Preconditions:
962 //
963 // Parameters:	inSource,	the bits data to translate
964 //
965 //				outType,	the type of data to convert to
966 //
967 //				outDestination,	where the output is written to
968 //
969 // Postconditions:
970 //
971 // Returns: B_NO_TRANSLATOR,	if the data is not in a supported
972 //								format
973 //
974 // B_ERROR, if there was an error allocating memory or some other
975 //			error
976 //
977 // B_OK, if successfully translated the data from the bits format
978 // ---------------------------------------------------------------
979 status_t
980 BMPTranslator::translate_from_bits(BPositionIO *inSource, uint32 outType,
981 	BPositionIO *outDestination)
982 {
983 	bool bheaderonly, bdataonly;
984 	bheaderonly = bdataonly = false;
985 
986 	TranslatorBitmap bitsHeader;
987 	status_t result;
988 	result = identify_bits_header(inSource, NULL, &bitsHeader);
989 	if (result != B_OK)
990 		return result;
991 
992 	// Translate B_TRANSLATOR_BITMAP to B_BMP_FORMAT
993 	if (outType == B_BMP_FORMAT) {
994 		// Set up BMP header
995 		BMPFileHeader fileHeader;
996 		fileHeader.magic = 'MB';
997 		fileHeader.reserved = 0;
998 
999 		MSInfoHeader msheader;
1000 		msheader.size = 40;
1001 		msheader.width =
1002 			static_cast<uint32> (bitsHeader.bounds.Width() + 1);
1003 		msheader.height =
1004 			static_cast<uint32> (bitsHeader.bounds.Height() + 1);
1005 		msheader.planes = 1;
1006 		msheader.xpixperm = 2835; // 72 dpi horizontal
1007 		msheader.ypixperm = 2835; // 72 dpi vertical
1008 		msheader.colorsused = 0;
1009 		msheader.colorsimportant = 0;
1010 
1011 		// determine fileSize / imagesize
1012 		switch (bitsHeader.colors) {
1013 			case B_RGB32:
1014 			case B_RGB32_BIG:
1015 			case B_RGBA32:
1016 			case B_RGBA32_BIG:
1017 			case B_RGB24:
1018 			case B_RGB24_BIG:
1019 			case B_RGB16:
1020 			case B_RGB16_BIG:
1021 			case B_RGB15:
1022 			case B_RGB15_BIG:
1023 			case B_RGBA15:
1024 			case B_RGBA15_BIG:
1025 			case B_CMYK32:
1026 			case B_CMY32:
1027 			case B_CMYA32:
1028 			case B_CMY24:
1029 
1030 				fileHeader.dataOffset = 54;
1031 				msheader.bitsperpixel = 24;
1032 				msheader.compression = BMP_NO_COMPRESS;
1033 				msheader.imagesize = get_rowbytes(msheader.width, 24) *
1034 					msheader.height;
1035 				fileHeader.fileSize = fileHeader.dataOffset +
1036 					msheader.imagesize;
1037 
1038 				break;
1039 
1040 			case B_CMAP8:
1041 			case B_GRAY8:
1042 
1043 				msheader.colorsused = 256;
1044 				msheader.colorsimportant = 256;
1045 				fileHeader.dataOffset = 54 + (4 * 256);
1046 				msheader.bitsperpixel = 8;
1047 				msheader.compression = BMP_NO_COMPRESS;
1048 				msheader.imagesize = get_rowbytes(msheader.width,
1049 					msheader.bitsperpixel) * msheader.height;
1050 				fileHeader.fileSize = fileHeader.dataOffset +
1051 					msheader.imagesize;
1052 
1053 				break;
1054 
1055 			case B_GRAY1:
1056 
1057 				msheader.colorsused = 2;
1058 				msheader.colorsimportant = 2;
1059 				fileHeader.dataOffset = 62;
1060 				msheader.bitsperpixel = 1;
1061 				msheader.compression = BMP_NO_COMPRESS;
1062 				msheader.imagesize = get_rowbytes(msheader.width,
1063 					msheader.bitsperpixel) * msheader.height;
1064 				fileHeader.fileSize = fileHeader.dataOffset +
1065 					msheader.imagesize;
1066 
1067 				break;
1068 
1069 			default:
1070 				return B_NO_TRANSLATOR;
1071 		}
1072 
1073 		// write out the BMP headers
1074 		if (bheaderonly || (!bheaderonly && !bdataonly)) {
1075 			result = write_bmp_headers(outDestination, fileHeader, msheader);
1076 			if (result != B_OK)
1077 				return result;
1078 		}
1079 		if (bheaderonly)
1080 			// if user only wants the header, bail out
1081 			// before the data is written
1082 			return result;
1083 
1084 		// write out the BMP pixel data
1085 		switch (bitsHeader.colors) {
1086 			case B_RGB32:
1087 			case B_RGB32_BIG:
1088 			case B_RGBA32:
1089 			case B_RGBA32_BIG:
1090 			case B_RGB24:
1091 			case B_RGB24_BIG:
1092 			case B_RGB16:
1093 			case B_RGB16_BIG:
1094 			case B_RGB15:
1095 			case B_RGB15_BIG:
1096 			case B_RGBA15:
1097 			case B_RGBA15_BIG:
1098 			case B_CMYK32:
1099 			case B_CMY32:
1100 			case B_CMYA32:
1101 			case B_CMY24:
1102 				return translate_from_bits_to_bmp24(inSource, outDestination,
1103 					bitsHeader.colors, msheader);
1104 
1105 			case B_CMAP8:
1106 			case B_GRAY8:
1107 			{
1108 				// write palette to BMP file
1109 				uint8 pal[1024];
1110 				uint8* palHandle = pal;
1111 				if (bitsHeader.colors == B_CMAP8) {
1112 					// write system palette
1113 					const color_map *pmap = system_colors();
1114 					if (!pmap)
1115 						return B_ERROR;
1116 					for (int32 i = 0; i < 256; i++) {
1117 						rgb_color c = pmap->color_list[i];
1118 						palHandle[0] = c.blue;
1119 						palHandle[1] = c.green;
1120 						palHandle[2] = c.red;
1121 						palHandle[3] = c.alpha;
1122 						palHandle += 4;
1123 					}
1124 				} else {
1125 					// write gray palette
1126 					for (int32 i = 0; i < 256; i++) {
1127 						palHandle[0] = i;
1128 						palHandle[1] = i;
1129 						palHandle[2] = i;
1130 						palHandle[3] = 255;
1131 						palHandle += 4;
1132 					}
1133 				}
1134 				ssize_t written = outDestination->Write(pal, 1024);
1135 				if (written < 0)
1136 					return written;
1137 				if (written != 1024)
1138 					return B_ERROR;
1139 
1140 				return translate_from_bits8_to_bmp8(inSource, outDestination,
1141 					bitsHeader.rowBytes, msheader);
1142 			}
1143 
1144 			case B_GRAY1:
1145 			{
1146 				// write monochrome palette to the BMP file
1147 				const uint32 monopal[] = { 0x00ffffff, 0x00000000 };
1148 				ssize_t written = outDestination->Write(monopal, 8);
1149 				if (written < 0)
1150 					return written;
1151 				if (written != 8)
1152 					return B_ERROR;
1153 
1154 				return translate_from_bits1_to_bmp1(inSource, outDestination,
1155 					bitsHeader.rowBytes, msheader);
1156 			}
1157 
1158 			default:
1159 				return B_NO_TRANSLATOR;
1160 		}
1161 	} else
1162 		return B_NO_TRANSLATOR;
1163 }
1164 
1165 // ---------------------------------------------------------------
1166 // translate_from_bmpnpal_to_bits
1167 //
1168 // Translates a non-palette BMP from inSource to the B_RGB32
1169 // bits format.
1170 //
1171 // Preconditions:
1172 //
1173 // Parameters: inSource,	the BMP data to be translated
1174 //
1175 // outDestination,	where the bits data will be written to
1176 //
1177 // msheader,	header information about the BMP to be written
1178 //
1179 // Postconditions:
1180 //
1181 // Returns: B_ERROR, if there is an error allocating memory
1182 //
1183 // B_OK, if all went well
1184 // ---------------------------------------------------------------
1185 status_t
1186 translate_from_bmpnpal_to_bits(BPositionIO *inSource,
1187 	BPositionIO *outDestination, MSInfoHeader &msheader)
1188 {
1189 	int32 bitsRowBytes = msheader.width * 4;
1190 	int32 bmpBytesPerPixel = msheader.bitsperpixel / 8;
1191 	int32 bmpRowBytes =
1192 		get_rowbytes(msheader.width, msheader.bitsperpixel);
1193 
1194 	// Setup outDestination so that it can be written to
1195 	// from the end of the file to the beginning instead of
1196 	// the other way around
1197 	off_t bitsFileSize = (bitsRowBytes * msheader.height) +
1198 		sizeof(TranslatorBitmap);
1199 	if (outDestination->SetSize(bitsFileSize) != B_OK) {
1200 		// This call should work for BFile and BMallocIO objects,
1201 		// but may not work for other BPositionIO based types
1202 		ERROR("BMPTranslator::translate_from_bmpnpal_to_bits() - failed to SetSize()\n");
1203 		return B_ERROR;
1204 	}
1205 	off_t bitsoffset = (msheader.height - 1) * bitsRowBytes;
1206 	outDestination->Seek(bitsoffset, SEEK_CUR);
1207 
1208 	// allocate row buffers
1209 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
1210 	if (!bmpRowData)
1211 		return B_NO_MEMORY;
1212 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
1213 	if (!bitsRowData) {
1214 		delete[] bmpRowData;
1215 		return B_NO_MEMORY;
1216 	}
1217 
1218 	// perform the actual translation
1219 	if (bmpBytesPerPixel != 4) {
1220 		// clean out buffer so that we don't have to write
1221 		// alpha for each row
1222 		memset(bitsRowData, 0xff, bitsRowBytes);
1223 	}
1224 
1225 	status_t ret = B_OK;
1226 
1227 	for (uint32 y = 0; y < msheader.height; y++) {
1228 		ssize_t read = inSource->Read(bmpRowData, bmpRowBytes);
1229 		if (read != bmpRowBytes) {
1230 			// break on read error
1231 			if (read >= 0)
1232 				ret = B_ERROR;
1233 			else
1234 				ret = read;
1235 			break;
1236 		}
1237 
1238 		if (bmpBytesPerPixel == 4) {
1239 			memcpy(bitsRowData, bmpRowData, bmpRowBytes);
1240 		} else {
1241 			uint8 *pBitsPixel = bitsRowData;
1242 			uint8 *pBmpPixel = bmpRowData;
1243 			for (uint32 i = 0; i < msheader.width; i++) {
1244 				pBitsPixel[0] = pBmpPixel[0];
1245 				pBitsPixel[1] = pBmpPixel[1];
1246 				pBitsPixel[2] = pBmpPixel[2];
1247 				pBitsPixel += 4;
1248 				pBmpPixel += bmpBytesPerPixel;
1249 			}
1250 		}
1251 		// write row and seek backward by two rows
1252 		ssize_t written = outDestination->Write(bitsRowData, bitsRowBytes);
1253 		outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1254 
1255 		if (written != bitsRowBytes) {
1256 			// break on write error
1257 			if (written >= 0)
1258 				ret = B_ERROR;
1259 			else
1260 				ret = read;
1261 			break;
1262 		}
1263 	}
1264 
1265 	delete[] bmpRowData;
1266 	delete[] bitsRowData;
1267 
1268 	return ret;
1269 }
1270 
1271 // ---------------------------------------------------------------
1272 // translate_from_bmppal_to_bits
1273 //
1274 // Translates an uncompressed, palette BMP from inSource to
1275 // the B_RGB32 bits format.
1276 //
1277 // Preconditions:
1278 //
1279 // Parameters: inSource,	the BMP data to be translated
1280 //
1281 // outDestination,	where the bits data will be written to
1282 //
1283 // msheader,	header information about the BMP to be written
1284 //
1285 // palette,	BMP palette for the BMP image
1286 //
1287 // frommsformat, true if BMP in inSource is in MS format,
1288 //				 false if it is in OS/2 format
1289 //
1290 // Postconditions:
1291 //
1292 // Returns: B_NO_MEMORY, if there is an error allocating memory
1293 //
1294 // B_OK, if all went well
1295 // ---------------------------------------------------------------
1296 status_t
1297 translate_from_bmppal_to_bits(BPositionIO *inSource,
1298 	BPositionIO *outDestination, MSInfoHeader &msheader,
1299 	const uint8 *palette, bool frommsformat)
1300 {
1301 	uint16 pixelsPerByte = 8 / msheader.bitsperpixel;
1302 	uint16 bitsPerPixel = msheader.bitsperpixel;
1303 	uint8 palBytesPerPixel;
1304 	if (frommsformat)
1305 		palBytesPerPixel = 4;
1306 	else
1307 		palBytesPerPixel = 3;
1308 
1309 	uint8 mask = 1;
1310 	mask = (mask << bitsPerPixel) - 1;
1311 
1312 	int32 bmpRowBytes =
1313 		get_rowbytes(msheader.width, msheader.bitsperpixel);
1314 	uint32 bmppixrow = 0;
1315 
1316 	// Setup outDestination so that it can be written to
1317 	// from the end of the file to the beginning instead of
1318 	// the other way around
1319 	int32 bitsRowBytes = msheader.width * 4;
1320 	off_t bitsFileSize = (bitsRowBytes * msheader.height) +
1321 		sizeof(TranslatorBitmap);
1322 	if (outDestination->SetSize(bitsFileSize) != B_OK)
1323 		// This call should work for BFile and BMallocIO objects,
1324 		// but may not work for other BPositionIO based types
1325 		return B_ERROR;
1326 	off_t bitsoffset = ((msheader.height - 1) * bitsRowBytes);
1327 	outDestination->Seek(bitsoffset, SEEK_CUR);
1328 
1329 	// allocate row buffers
1330 	uint8 *bmpRowData = new (nothrow) uint8[bmpRowBytes];
1331 	if (!bmpRowData)
1332 		return B_NO_MEMORY;
1333 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
1334 	if (!bitsRowData) {
1335 		delete[] bmpRowData;
1336 		return B_NO_MEMORY;
1337 	}
1338 	memset(bitsRowData, 0xff, bitsRowBytes);
1339 	ssize_t rd = inSource->Read(bmpRowData, bmpRowBytes);
1340 	while (rd == static_cast<ssize_t>(bmpRowBytes)) {
1341 		for (uint32 i = 0; i < msheader.width; i++) {
1342 			uint8 indices = (bmpRowData + (i / pixelsPerByte))[0];
1343 			uint8 index;
1344 			index = (indices >>
1345 				(bitsPerPixel * ((pixelsPerByte - 1) -
1346 					(i % pixelsPerByte)))) & mask;
1347 			memcpy(bitsRowData + (i * 4),
1348 				palette + (index * palBytesPerPixel), 3);
1349 		}
1350 
1351 		outDestination->Write(bitsRowData, bitsRowBytes);
1352 		bmppixrow++;
1353 		// if I've read all of the pixel data, break
1354 		// out of the loop so I don't try to read
1355 		// non-pixel data
1356 		if (bmppixrow == msheader.height)
1357 			break;
1358 
1359 		outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1360 		rd = inSource->Read(bmpRowData, bmpRowBytes);
1361 	}
1362 
1363 	delete[] bmpRowData;
1364 	delete[] bitsRowData;
1365 
1366 	return B_OK;
1367 }
1368 
1369 
1370 // ---------------------------------------------------------------
1371 // pixelcpy
1372 //
1373 // Copies count 32-bit pixels with a color value of pixel to dest.
1374 //
1375 // Preconditions:
1376 //
1377 // Parameters:	dest,	where the pixel data will be copied to
1378 //
1379 //				pixel,	the 32-bit color value to copy to dest
1380 //						count times
1381 //
1382 //				count,	the number of times pixel is copied to
1383 //						dest
1384 //
1385 // Postconditions:
1386 //
1387 // Returns:
1388 // ---------------------------------------------------------------
1389 void
1390 pixelcpy(uint8 *dest, uint32 pixel, uint32 count)
1391 {
1392 	for (uint32 i = 0; i < count; i++) {
1393 		memcpy(dest, &pixel, 3);
1394 		dest += 4;
1395 	}
1396 }
1397 
1398 // ---------------------------------------------------------------
1399 // translate_from_bmppalr_to_bits
1400 //
1401 // Translates an RLE compressed, palette BMP from inSource to
1402 // the B_RGB32 bits format. Currently, this code is not as
1403 // memory effcient as it could be. It assumes that the BMP
1404 // from inSource is relatively small.
1405 //
1406 // Preconditions:
1407 //
1408 // Parameters: inSource,	the BMP data to be translated
1409 //
1410 // outDestination,	where the bits data will be written to
1411 //
1412 // datasize, number of bytes of data needed for the bits output
1413 //
1414 // msheader,	header information about the BMP to be written
1415 //
1416 // palette,	BMP palette for data in inSource
1417 //
1418 // Postconditions:
1419 //
1420 // Returns: B_ERROR, if there is an error allocating memory
1421 //
1422 // B_OK, if all went well
1423 // ---------------------------------------------------------------
1424 status_t
1425 translate_from_bmppalr_to_bits(BPositionIO *inSource,
1426 	BPositionIO *outDestination, int32 datasize, MSInfoHeader &msheader,
1427 	const uint8 *palette)
1428 {
1429 	uint16 pixelsPerByte = 8 / msheader.bitsperpixel;
1430 	uint16 bitsPerPixel = msheader.bitsperpixel;
1431 	uint8 mask = (1 << bitsPerPixel) - 1;
1432 
1433 	uint8 count, indices, index;
1434 	// Setup outDestination so that it can be written to
1435 	// from the end of the file to the beginning instead of
1436 	// the other way around
1437 	int32 bitsRowBytes = msheader.width * 4;
1438 	off_t bitsFileSize = (bitsRowBytes * msheader.height) +
1439 		sizeof(TranslatorBitmap);
1440 	if (outDestination->SetSize(bitsFileSize) != B_OK)
1441 		// This call should work for BFile and BMallocIO objects,
1442 		// but may not work for other BPositionIO based types
1443 		return B_ERROR;
1444 	uint8 *bitsRowData = new (nothrow) uint8[bitsRowBytes];
1445 	if (!bitsRowData)
1446 		return B_NO_MEMORY;
1447 	memset(bitsRowData, 0xff, bitsRowBytes);
1448 	uint32 bmppixcol = 0, bmppixrow = 0;
1449 	uint32 defaultcolor = *(uint32*)palette;
1450 	// set bits output to last row in the image
1451 	off_t bitsoffset = ((msheader.height - (bmppixrow + 1)) * bitsRowBytes) +
1452 		(bmppixcol * 4);
1453 	outDestination->Seek(bitsoffset, SEEK_CUR);
1454 	ssize_t rd = inSource->Read(&count, 1);
1455 	while (rd > 0) {
1456 		// repeated color
1457 		if (count) {
1458 			// abort if all of the pixels in the row
1459 			// have already been drawn to
1460 			if (bmppixcol == msheader.width) {
1461 				rd = -1;
1462 				break;
1463 			}
1464 			// if count is greater than the number of
1465 			// pixels remaining in the current row,
1466 			// only process the correct number of pixels
1467 			// remaining in the row
1468 			if (count + bmppixcol > msheader.width)
1469 				count = msheader.width - bmppixcol;
1470 
1471 			rd = inSource->Read(&indices, 1);
1472 			if (rd != 1) {
1473 				rd = -1;
1474 				break;
1475 			}
1476 			for (uint8 i = 0; i < count; i++) {
1477 				index = (indices >> (bitsPerPixel * ((pixelsPerByte - 1) -
1478 					(i % pixelsPerByte)))) & mask;
1479 				memcpy(bitsRowData + (bmppixcol*4), palette + (index*4), 3);
1480 				bmppixcol++;
1481 			}
1482 		// special code
1483 		} else {
1484 			uint8 code;
1485 			rd = inSource->Read(&code, 1);
1486 			if (rd != 1) {
1487 				rd = -1;
1488 				break;
1489 			}
1490 			switch (code) {
1491 				// end of line
1492 				case 0:
1493 					// if there are columns remaing on this
1494 					// line, set them to the color at index zero
1495 					if (bmppixcol < msheader.width)
1496 						pixelcpy(bitsRowData + (bmppixcol * 4),
1497 							defaultcolor, msheader.width - bmppixcol);
1498 					outDestination->Write(bitsRowData, bitsRowBytes);
1499 					bmppixcol = 0;
1500 					bmppixrow++;
1501 					if (bmppixrow < msheader.height)
1502 						outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1503 					break;
1504 
1505 				// end of bitmap
1506 				case 1:
1507 					// if at the end of a row
1508 					if (bmppixcol == msheader.width) {
1509 						outDestination->Write(bitsRowData, bitsRowBytes);
1510 						bmppixcol = 0;
1511 						bmppixrow++;
1512 						if (bmppixrow < msheader.height)
1513 							outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1514 					}
1515 
1516 					while (bmppixrow < msheader.height) {
1517 						pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor,
1518 							msheader.width - bmppixcol);
1519 						outDestination->Write(bitsRowData, bitsRowBytes);
1520 						bmppixcol = 0;
1521 						bmppixrow++;
1522 						if (bmppixrow < msheader.height)
1523 							outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1524 					}
1525 					rd = 0;
1526 						// break out of while loop
1527 					break;
1528 
1529 				// delta, skip several rows and/or columns and
1530 				// fill the skipped pixels with the default color
1531 				case 2:
1532 				{
1533 					uint8 da[2], lastcol, dx, dy;
1534 					rd = inSource->Read(da, 2);
1535 					if (rd != 2) {
1536 						rd = -1;
1537 						break;
1538 					}
1539 					dx = da[0];
1540 					dy = da[1];
1541 
1542 					// abort if dx or dy is too large
1543 					if ((dx + bmppixcol >= msheader.width) ||
1544 						(dy + bmppixrow >= msheader.height)) {
1545 						rd = -1;
1546 						break;
1547 					}
1548 
1549 					lastcol = bmppixcol;
1550 
1551 					// set all pixels to the first entry in
1552 					// the palette, for the number of rows skipped
1553 					while (dy > 0) {
1554 						pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor,
1555 							msheader.width - bmppixcol);
1556 						outDestination->Write(bitsRowData, bitsRowBytes);
1557 						bmppixcol = 0;
1558 						bmppixrow++;
1559 						dy--;
1560 						outDestination->Seek(bitsRowBytes * -2, SEEK_CUR);
1561 					}
1562 
1563 					if (bmppixcol < static_cast<uint32>(lastcol + dx)) {
1564 						pixelcpy(bitsRowData + (bmppixcol * 4), defaultcolor,
1565 							dx + lastcol - bmppixcol);
1566 						bmppixcol = dx + lastcol;
1567 					}
1568 
1569 					break;
1570 				}
1571 
1572 				// code >= 3
1573 				// read code uncompressed indices
1574 				default:
1575 					// abort if all of the pixels in the row
1576 					// have already been drawn to
1577 					if (bmppixcol == msheader.width) {
1578 						rd = -1;
1579 						break;
1580 					}
1581 					// if code is greater than the number of
1582 					// pixels remaining in the current row,
1583 					// only process the correct number of pixels
1584 					// remaining in the row
1585 					if (code + bmppixcol > msheader.width)
1586 						code = msheader.width - bmppixcol;
1587 
1588 					uint8 uncomp[256];
1589 					int32 padding;
1590 					if (!(code % pixelsPerByte))
1591 						padding = (code / pixelsPerByte) % 2;
1592 					else
1593 						padding = ((code + pixelsPerByte -
1594 							(code % pixelsPerByte)) / pixelsPerByte) % 2;
1595 					int32 uncompBytes = (code / pixelsPerByte) +
1596 						((code % pixelsPerByte) ? 1 : 0) + padding;
1597 					rd = inSource->Read(uncomp, uncompBytes);
1598 					if (rd != uncompBytes) {
1599 						rd = -1;
1600 						break;
1601 					}
1602 					for (uint8 i = 0; i < code; i++) {
1603 						indices = (uncomp + (i / pixelsPerByte))[0];
1604 						index = (indices >>
1605 							(bitsPerPixel * ((pixelsPerByte - 1) -
1606 								(i % pixelsPerByte)))) & mask;
1607 						memcpy(bitsRowData + (bmppixcol * 4),
1608 							palette + (index * 4), 3);
1609 						bmppixcol++;
1610 					}
1611 
1612 					break;
1613 			}
1614 		}
1615 		if (rd > 0)
1616 			rd = inSource->Read(&count, 1);
1617 	}
1618 
1619 	delete[] bitsRowData;
1620 
1621 	if (!rd)
1622 		return B_OK;
1623 	else
1624 		return B_NO_TRANSLATOR;
1625 }
1626 
1627 // ---------------------------------------------------------------
1628 // translate_from_bmp
1629 //
1630 // Convert the data in inSource from the BMP format
1631 // to the format specified in outType (either bits or BMP).
1632 //
1633 // Preconditions:
1634 //
1635 // Parameters:	inSource,	the bits data to translate
1636 //
1637 //				outType,	the type of data to convert to
1638 //
1639 //				outDestination,	where the output is written to
1640 //
1641 // Postconditions:
1642 //
1643 // Returns: B_NO_TRANSLATOR,	if the data is not in a supported
1644 //								format
1645 //
1646 // B_ERROR, if there was an error allocating memory or some other
1647 //			error
1648 //
1649 // B_OK, if successfully translated the data from the bits format
1650 // ---------------------------------------------------------------
1651 status_t
1652 BMPTranslator::translate_from_bmp(BPositionIO *inSource, uint32 outType,
1653 	BPositionIO *outDestination)
1654 {
1655 	bool bheaderonly, bdataonly;
1656 	bheaderonly = bdataonly = false;
1657 
1658 	BMPFileHeader fileHeader;
1659 	MSInfoHeader msheader;
1660 	bool frommsformat;
1661 	off_t os2skip = 0;
1662 
1663 	status_t result;
1664 	result = identify_bmp_header(inSource, NULL, &fileHeader, &msheader,
1665 		&frommsformat, &os2skip);
1666 	if (result != B_OK) {
1667 		INFO("BMPTranslator::translate_from_bmp() - identify_bmp_header failed\n");
1668 		return result;
1669 	}
1670 
1671 	// if the user wants to translate a BMP to a BMP, easy enough :)
1672 	if (outType == B_BMP_FORMAT) {
1673 		// write out the BMP headers
1674 		if (bheaderonly || (!bheaderonly && !bdataonly)) {
1675 			result = write_bmp_headers(outDestination, fileHeader, msheader);
1676 			if (result != B_OK)
1677 				return result;
1678 		}
1679 		if (bheaderonly)
1680 			// if the user only wants the header,
1681 			// bail before it is written
1682 			return result;
1683 
1684 		uint8 buf[1024];
1685 		ssize_t rd;
1686 		uint32 rdtotal = 54;
1687 		if (!frommsformat && (msheader.bitsperpixel == 1 ||
1688 			msheader.bitsperpixel == 4 || msheader.bitsperpixel == 8)) {
1689 			// if OS/2 paletted format, convert palette to MS format
1690 			uint16 ncolors = 1 << msheader.bitsperpixel;
1691 			rd = inSource->Read(buf, ncolors * 3);
1692 			if (rd != ncolors * 3)
1693 				return B_NO_TRANSLATOR;
1694 			uint8 mspalent[4] = {0, 0, 0, 0};
1695 			for (uint16 i = 0; i < ncolors; i++) {
1696 				memcpy(mspalent, buf + (i * 3), 3);
1697 				outDestination->Write(mspalent, 4);
1698 			}
1699 			rdtotal = fileHeader.dataOffset;
1700 		}
1701 		// if there is junk between the OS/2 headers and
1702 		// the actual data, skip it
1703 		if (!frommsformat && os2skip)
1704 			inSource->Seek(os2skip, SEEK_CUR);
1705 
1706 		rd = min(1024, fileHeader.fileSize - rdtotal);
1707 		rd = inSource->Read(buf, rd);
1708 		while (rd > 0) {
1709 			outDestination->Write(buf, rd);
1710 			rdtotal += rd;
1711 			rd = min(1024, fileHeader.fileSize - rdtotal);
1712 			rd = inSource->Read(buf, rd);
1713 		}
1714 		if (rd == 0)
1715 			return B_OK;
1716 		else
1717 			return B_ERROR;
1718 
1719 	// if translating a BMP to a Be Bitmap
1720 	} else if (outType == B_TRANSLATOR_BITMAP) {
1721 		TranslatorBitmap bitsHeader;
1722 		bitsHeader.magic = B_TRANSLATOR_BITMAP;
1723 		bitsHeader.bounds.left = 0;
1724 		bitsHeader.bounds.top = 0;
1725 		bitsHeader.bounds.right = msheader.width - 1;
1726 		bitsHeader.bounds.bottom = msheader.height - 1;
1727 
1728 		// read in palette and/or skip non-BMP data
1729 		uint8 bmppalette[1024];
1730 		off_t nskip = 0;
1731 		if (msheader.bitsperpixel == 1 ||
1732 			msheader.bitsperpixel == 4 ||
1733 			msheader.bitsperpixel == 8) {
1734 
1735 			uint8 palBytesPerPixel;
1736 			if (frommsformat)
1737 				palBytesPerPixel = 4;
1738 			else
1739 				palBytesPerPixel = 3;
1740 
1741 			if (!msheader.colorsused)
1742 				msheader.colorsused = 1 << msheader.bitsperpixel;
1743 
1744 			if (inSource->Read(bmppalette, msheader.colorsused *
1745 				palBytesPerPixel) !=
1746 					(off_t) msheader.colorsused * palBytesPerPixel)
1747 				return B_NO_TRANSLATOR;
1748 
1749 			// skip over non-BMP data
1750 			if (frommsformat) {
1751 				if (fileHeader.dataOffset > (msheader.colorsused *
1752 					palBytesPerPixel) + 54)
1753 					nskip = fileHeader.dataOffset -
1754 						((msheader.colorsused * palBytesPerPixel) + 54);
1755 			} else
1756 				nskip = os2skip;
1757 		} else if (fileHeader.dataOffset > 54)
1758 			// skip over non-BMP data
1759 			nskip = fileHeader.dataOffset - 54;
1760 
1761 		if (nskip > 0 && inSource->Seek(nskip, SEEK_CUR) < 0)
1762 			return B_NO_TRANSLATOR;
1763 
1764 		bitsHeader.rowBytes = msheader.width * 4;
1765 		bitsHeader.colors = B_RGB32;
1766 		int32 datasize = bitsHeader.rowBytes * msheader.height;
1767 		bitsHeader.dataSize = datasize;
1768 
1769 		// write out Be's Bitmap header
1770 		if (bheaderonly || (!bheaderonly && !bdataonly)) {
1771 			if (swap_data(B_UINT32_TYPE, &bitsHeader,
1772 				sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK)
1773 				return B_ERROR;
1774 			outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
1775 		}
1776 		if (bheaderonly)
1777 			// if the user only wants the header,
1778 			// bail before the data is written
1779 			return B_OK;
1780 
1781 		// write out the actual image data
1782 		switch (msheader.bitsperpixel) {
1783 			case 32:
1784 			case 24:
1785 				return translate_from_bmpnpal_to_bits(inSource,
1786 					outDestination, msheader);
1787 
1788 			case 8:
1789 				// 8 bit BMP with NO compression
1790 				if (msheader.compression == BMP_NO_COMPRESS)
1791 					return translate_from_bmppal_to_bits(inSource,
1792 						outDestination, msheader, bmppalette, frommsformat);
1793 
1794 				// 8 bit RLE compressed BMP
1795 				else if (msheader.compression == BMP_RLE8_COMPRESS)
1796 					return translate_from_bmppalr_to_bits(inSource,
1797 						outDestination, datasize, msheader, bmppalette);
1798 				else
1799 					return B_NO_TRANSLATOR;
1800 
1801 			case 4:
1802 				// 4 bit BMP with NO compression
1803 				if (!msheader.compression)
1804 					return translate_from_bmppal_to_bits(inSource,
1805 						outDestination, msheader, bmppalette, frommsformat);
1806 
1807 				// 4 bit RLE compressed BMP
1808 				else if (msheader.compression == BMP_RLE4_COMPRESS)
1809 					return translate_from_bmppalr_to_bits(inSource,
1810 						outDestination, datasize, msheader, bmppalette);
1811 				else
1812 					return B_NO_TRANSLATOR;
1813 
1814 			case 1:
1815 				return translate_from_bmppal_to_bits(inSource,
1816 					outDestination, msheader, bmppalette, frommsformat);
1817 
1818 			default:
1819 				return B_NO_TRANSLATOR;
1820 		}
1821 
1822 	} else
1823 		return B_NO_TRANSLATOR;
1824 }
1825 
1826 // ---------------------------------------------------------------
1827 // DerivedTranslate
1828 //
1829 // Translates the data in inSource to the type outType and stores
1830 // the translated data in outDestination.
1831 //
1832 // Preconditions:
1833 //
1834 // Parameters:	inSource,	the data to be translated
1835 //
1836 //				inInfo,	hint about the data in inSource (not used)
1837 //
1838 //				ioExtension,	configuration options for the
1839 //								translator
1840 //
1841 //				outType,	the type to convert inSource to
1842 //
1843 //				outDestination,	where the translated data is
1844 //								put
1845 //
1846 //				baseType, indicates whether inSource is in the
1847 //				          bits format, not in the bits format or
1848 //				          is unknown
1849 //
1850 // Postconditions:
1851 //
1852 // Returns: B_BAD_VALUE, if the options in ioExtension are bad
1853 //
1854 // B_NO_TRANSLATOR, if this translator doesn't understand the data
1855 //
1856 // B_ERROR, if there was an error allocating memory or converting
1857 //          data
1858 //
1859 // B_OK, if all went well
1860 // ---------------------------------------------------------------
1861 status_t
1862 BMPTranslator::DerivedTranslate(BPositionIO *inSource,
1863 		const translator_info *inInfo, BMessage *ioExtension,
1864 		uint32 outType, BPositionIO *outDestination, int32 baseType)
1865 {
1866 	if (baseType == 1)
1867 		// if inSource is in bits format
1868 		return translate_from_bits(inSource, outType, outDestination);
1869 	else if (baseType == 0)
1870 		// if inSource is NOT in bits format
1871 		return translate_from_bmp(inSource, outType, outDestination);
1872 	else
1873 		return B_NO_TRANSLATOR;
1874 }
1875 
1876 BView *
1877 BMPTranslator::NewConfigView(TranslatorSettings *settings)
1878 {
1879 	return new BMPView(BRect(0, 0, 225, 175), "BMPTranslator Settings",
1880 		B_FOLLOW_ALL, B_WILL_DRAW, settings);
1881 }
1882