⛏️ index : haiku.git

/*****************************************************************************/
// TGATranslator
// Written by Michael Wilber, Haiku Translation Kit Team
//
// TGATranslator.cpp
//
// This BTranslator based object is for opening and writing TGA files.
//
//
// Copyright (c) 2002-2009, Haiku, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/

#include <string.h>
#include <stdio.h>

#include <Catalog.h>

#include "TGATranslator.h"
#include "TGAView.h"
#include "StreamBuffer.h"

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "TGATranslator"

// The input formats that this translator supports.
static const translation_format sInputFormats[] = {
	{
		B_TRANSLATOR_BITMAP,
		B_TRANSLATOR_BITMAP,
		BBT_IN_QUALITY,
		BBT_IN_CAPABILITY,
		"image/x-be-bitmap",
		"Be Bitmap Format (TGATranslator)"
	},
	{
		B_TGA_FORMAT,
		B_TRANSLATOR_BITMAP,
		TGA_IN_QUALITY,
		TGA_IN_CAPABILITY,
		"image/x-targa",
		"Targa image"
	}
};

// The output formats that this translator supports.
static const translation_format sOutputFormats[] = {
	{
		B_TRANSLATOR_BITMAP,
		B_TRANSLATOR_BITMAP,
		BBT_OUT_QUALITY,
		BBT_OUT_CAPABILITY,
		"image/x-be-bitmap",
		"Be Bitmap Format (TGATranslator)"
	},
	{
		B_TGA_FORMAT,
		B_TRANSLATOR_BITMAP,
		TGA_OUT_QUALITY,
		TGA_OUT_CAPABILITY,
		"image/x-targa",
		"Targa image"
	}
};

// Default settings for the Translator
static const TranSetting sDefaultSettings[] = {
	{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
	{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false},
	{TGA_SETTING_RLE, TRAN_SETTING_BOOL, false},
		// RLE compression is off by default
	{TGA_SETTING_IGNORE_ALPHA, TRAN_SETTING_BOOL, false}
		// Don't ignore the alpha channel by default
};

const uint32 kNumInputFormats = sizeof(sInputFormats) / sizeof(translation_format);
const uint32 kNumOutputFormats = sizeof(sOutputFormats) / sizeof(translation_format);
const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) / sizeof(TranSetting);


// ---------------------------------------------------------------
// make_nth_translator
//
// Creates a TGATranslator object to be used by BTranslatorRoster
//
// Preconditions:
//
// Parameters: n,		The translator to return. Since
//						TGATranslator only publishes one
//						translator, it only returns a
//						TGATranslator if n == 0
//
//             you, 	The image_id of the add-on that
//						contains code (not used).
//
//             flags,	Has no meaning yet, should be 0.
//
// Postconditions:
//
// Returns: NULL if n is not zero,
//          a new TGATranslator if n is zero
// ---------------------------------------------------------------
BTranslator *
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
{
	BTranslator *ptranslator = NULL;
	if (!n)
		ptranslator = new(std::nothrow) TGATranslator();

	return ptranslator;
}

// ---------------------------------------------------------------
// Constructor
//
// Sets up the version info and the name of the translator so that
// these values can be returned when they are requested.
//
// Preconditions:
//
// Parameters:
//
// Postconditions:
//
// Returns:
// ---------------------------------------------------------------
TGATranslator::TGATranslator()
	: BaseTranslator(B_TRANSLATE("TGA images"),
		B_TRANSLATE("TGA image translator"),
		TGA_TRANSLATOR_VERSION,
		sInputFormats, kNumInputFormats,
		sOutputFormats, kNumOutputFormats,
		"TGATranslator_Settings",
		sDefaultSettings, kNumDefaultSettings,
		B_TRANSLATOR_BITMAP, B_TGA_FORMAT)
{
}

// ---------------------------------------------------------------
// Destructor
//
// Does nothing
//
// Preconditions:
//
// Parameters:
//
// Postconditions:
//
// Returns:
// ---------------------------------------------------------------
//
// NOTE: It may be the case, that under Be's libtranslation.so,
// that this destructor will never be called
TGATranslator::~TGATranslator()
{
}

uint8
TGATranslator::tga_alphabits(TGAFileHeader &filehead, TGAColorMapSpec &mapspec,
	TGAImageSpec &imagespec)
{
	if (fSettings->SetGetBool(TGA_SETTING_IGNORE_ALPHA))
		return 0;
	else {
		uint8 nalpha;
		if (filehead.imagetype == TGA_NOCOMP_COLORMAP ||
			filehead.imagetype == TGA_RLE_COLORMAP) {
			// color mapped images

			if (mapspec.entrysize == 32)
				nalpha = 8;
			else if (mapspec.entrysize == 16)
				nalpha = 1;
			else
				nalpha = 0;

		} else {
			// non-color mapped images

			if (imagespec.depth == 32)
				// Some programs that generate 32-bit TGA files
				// have an alpha channel, but have an incorrect
				// descriptor which says there are no alpha bits.
				// This logic is so that the alpha data can be
				// obtained from TGA files that lie.
				nalpha = 8;
			else
				nalpha = imagespec.descriptor & TGA_DESC_ALPHABITS;
		}

		return nalpha;
	}
}

// ---------------------------------------------------------------
// identify_tga_header
//
// Determines if the data in inSource is in the TGA format.
// If it is, it returns info about the data in inSource
// to outInfo, pfileheader, pmapspec and pimagespec.
//
// Preconditions:
//
// Parameters:	inSource,	The source of the image data
//
//				outInfo,	Information about the translator
//							is copied here
//
//				pfileheader,	File header info for the TGA is
//								copied here after it is read from
//								the file.
//
//				pmapspec,	color map info for the TGA is copied
//							here after it is read from the file
//
//				pimagespec,	Info about the image width/height etc.
//							is copied here after it is read from
//							the file
//
//
// Postconditions:
//
// Returns: B_NO_TRANSLATOR,	if the data does not look like
//								TGA format data
//
// B_ERROR,	if the header data could not be converted to host
//			format
//
// B_OK,	if the data looks like bits data and no errors were
//			encountered
// ---------------------------------------------------------------
status_t
identify_tga_header(BPositionIO *inSource, translator_info *outInfo,
	TGAFileHeader *pfileheader = NULL, TGAColorMapSpec *pmapspec = NULL,
	TGAImageSpec *pimagespec = NULL)
{
	uint8 buf[TGA_HEADERS_SIZE];

	// read in the rest of the TGA headers
	ssize_t size = TGA_HEADERS_SIZE;
	if (size > 0 && inSource->Read(buf, size) != size)
		return B_NO_TRANSLATOR;

	// Read in TGA file header
	TGAFileHeader fileheader;
	fileheader.idlength = buf[0];

	fileheader.colormaptype = buf[1];
	if (fileheader.colormaptype > 1)
		return B_NO_TRANSLATOR;

	fileheader.imagetype = buf[2];
	if ((fileheader.imagetype > 3 && fileheader.imagetype < 9) ||
		fileheader.imagetype > 11)
		return B_NO_TRANSLATOR;
	if ((fileheader.colormaptype == TGA_NO_COLORMAP &&
		fileheader.imagetype == TGA_NOCOMP_COLORMAP) ||
		(fileheader.colormaptype == TGA_COLORMAP &&
			fileheader.imagetype != TGA_NOCOMP_COLORMAP &&
			fileheader.imagetype != TGA_RLE_COLORMAP))
		return B_NO_TRANSLATOR;

	// Read in TGA color map spec
	TGAColorMapSpec mapspec;
	memcpy(&mapspec.firstentry, buf + 3, 2);
	mapspec.firstentry = B_LENDIAN_TO_HOST_INT16(mapspec.firstentry);
	if (fileheader.colormaptype == 0 && mapspec.firstentry != 0)
		return B_NO_TRANSLATOR;

	memcpy(&mapspec.length, buf + 5, 2);
	mapspec.length = B_LENDIAN_TO_HOST_INT16(mapspec.length);
	if (fileheader.colormaptype == TGA_NO_COLORMAP &&
		mapspec.length != 0)
		return B_NO_TRANSLATOR;
	if (fileheader.colormaptype == TGA_COLORMAP &&
		mapspec.length == 0)
		return B_NO_TRANSLATOR;

	mapspec.entrysize = buf[7];
	if (fileheader.colormaptype == TGA_NO_COLORMAP &&
		mapspec.entrysize != 0)
		return B_NO_TRANSLATOR;
	if (fileheader.colormaptype == TGA_COLORMAP &&
		mapspec.entrysize != 15 && mapspec.entrysize != 16 &&
		mapspec.entrysize != 24 && mapspec.entrysize != 32)
		return B_NO_TRANSLATOR;

	// Read in TGA image spec
	TGAImageSpec imagespec;
	memcpy(&imagespec.xorigin, buf + 8, 2);
	imagespec.xorigin = B_LENDIAN_TO_HOST_INT16(imagespec.xorigin);

	memcpy(&imagespec.yorigin, buf + 10, 2);
	imagespec.yorigin = B_LENDIAN_TO_HOST_INT16(imagespec.yorigin);

	memcpy(&imagespec.width, buf + 12, 2);
	imagespec.width = B_LENDIAN_TO_HOST_INT16(imagespec.width);
	if (imagespec.width == 0)
		return B_NO_TRANSLATOR;

	memcpy(&imagespec.height, buf + 14, 2);
	imagespec.height = B_LENDIAN_TO_HOST_INT16(imagespec.height);
	if (imagespec.height == 0)
		return B_NO_TRANSLATOR;

	imagespec.depth = buf[16];
	if (imagespec.depth < 1 || imagespec.depth > 32)
		return B_NO_TRANSLATOR;
	if ((fileheader.imagetype == TGA_NOCOMP_TRUECOLOR ||
			fileheader.imagetype == TGA_RLE_TRUECOLOR) &&
		imagespec.depth != 15 && imagespec.depth != 16 &&
		imagespec.depth != 24 && imagespec.depth != 32)
		return B_NO_TRANSLATOR;
	if ((fileheader.imagetype == TGA_NOCOMP_BW ||
			fileheader.imagetype == TGA_RLE_BW) &&
		imagespec.depth != 8)
		return B_NO_TRANSLATOR;
	if (fileheader.colormaptype == TGA_COLORMAP &&
		imagespec.depth != 8)
		return B_NO_TRANSLATOR;

	imagespec.descriptor = buf[17];
	// images ordered from Right to Left (rather than Left to Right)
	// are not supported
	if ((imagespec.descriptor & TGA_ORIGIN_HORZ_BIT) != TGA_ORIGIN_LEFT)
		return B_NO_TRANSLATOR;
	// unused descriptor bits, these bits must be zero
	if (imagespec.descriptor & TGA_DESC_BITS76)
		return B_NO_TRANSLATOR;
	if ((fileheader.imagetype == TGA_NOCOMP_TRUECOLOR ||
		fileheader.imagetype == TGA_RLE_TRUECOLOR) &&
		imagespec.depth == 32 &&
		(imagespec.descriptor & TGA_DESC_ALPHABITS) != 8 &&
		(imagespec.descriptor & TGA_DESC_ALPHABITS) != 0)
		return B_NO_TRANSLATOR;
	if ((fileheader.imagetype == TGA_NOCOMP_TRUECOLOR ||
		fileheader.imagetype == TGA_RLE_TRUECOLOR) &&
		imagespec.depth == 24 &&
		(imagespec.descriptor & TGA_DESC_ALPHABITS) != 0)
		return B_NO_TRANSLATOR;
	if ((fileheader.imagetype == TGA_NOCOMP_TRUECOLOR ||
		fileheader.imagetype == TGA_RLE_TRUECOLOR) &&
		imagespec.depth == 16 &&
		(imagespec.descriptor & TGA_DESC_ALPHABITS) != 1 &&
		(imagespec.descriptor & TGA_DESC_ALPHABITS) != 0)
	if ((fileheader.imagetype == TGA_NOCOMP_TRUECOLOR ||
		fileheader.imagetype == TGA_RLE_TRUECOLOR) &&
		imagespec.depth == 15 &&
		(imagespec.descriptor & TGA_DESC_ALPHABITS) != 0)
		return B_NO_TRANSLATOR;

	// Fill in headers passed to this function
	if (pfileheader) {
		pfileheader->idlength = fileheader.idlength;
		pfileheader->colormaptype = fileheader.colormaptype;
		pfileheader->imagetype = fileheader.imagetype;
	}
	if (pmapspec) {
		pmapspec->firstentry = mapspec.firstentry;
		pmapspec->length = mapspec.length;
		pmapspec->entrysize = mapspec.entrysize;
	}
	if (pimagespec) {
		pimagespec->xorigin = imagespec.xorigin;
		pimagespec->yorigin = imagespec.yorigin;
		pimagespec->width = imagespec.width;
		pimagespec->height = imagespec.height;
		pimagespec->depth = imagespec.depth;
		pimagespec->descriptor = imagespec.descriptor;
	}

	if (outInfo) {
		outInfo->type = B_TGA_FORMAT;
		outInfo->group = B_TRANSLATOR_BITMAP;
		outInfo->quality = TGA_IN_QUALITY;
		outInfo->capability = TGA_IN_CAPABILITY;
		switch (fileheader.imagetype) {
			case TGA_NOCOMP_COLORMAP:
				snprintf(outInfo->name, sizeof(outInfo->name),
					B_TRANSLATE("Targa image (%d bits colormap)"),
					imagespec.depth);
				break;
			case TGA_NOCOMP_TRUECOLOR:
				snprintf(outInfo->name, sizeof(outInfo->name),
					B_TRANSLATE("Targa image (%d bits truecolor)"),
					imagespec.depth);
				break;
			case TGA_RLE_COLORMAP:
				snprintf(outInfo->name, sizeof(outInfo->name),
					B_TRANSLATE("Targa image (%d bits RLE colormap)"),
					imagespec.depth);
				break;
			case TGA_RLE_TRUECOLOR:
				snprintf(outInfo->name, sizeof(outInfo->name),
					B_TRANSLATE("Targa image (%d bits RLE truecolor)"),
					imagespec.depth);
				break;
			case TGA_RLE_BW:
				snprintf(outInfo->name, sizeof(outInfo->name),
					B_TRANSLATE("Targa image (%d bits RLE gray)"),
					imagespec.depth);
				break;
			case TGA_NOCOMP_BW:
			default:
				snprintf(outInfo->name, sizeof(outInfo->name),
					B_TRANSLATE("Targa image (%d bits gray)"),
					imagespec.depth);
				break;

		}
		strcpy(outInfo->MIME, "image/x-targa");
	}

	return B_OK;
}

status_t
TGATranslator::DerivedIdentify(BPositionIO *inSource,
	const translation_format *inFormat, BMessage *ioExtension,
	translator_info *outInfo, uint32 outType)
{
	return identify_tga_header(inSource, outInfo);
}

// Convert width pixels from pbits to TGA format, storing the
// result in ptga
status_t
pix_bits_to_tga(uint8 *pbits, uint8 *ptga, color_space fromspace,
	uint16 width, const color_map *pmap, int32 bitsBytesPerPixel)
{
	status_t bytescopied = 0;

	switch (fromspace) {
		case B_RGBA32:
			bytescopied = width * 4;
			memcpy(ptga, pbits, bytescopied);
			break;

		case B_RGBA32_BIG:
			bytescopied = width * 4;
			while (width--) {
				ptga[0] = pbits[3];
				ptga[1] = pbits[2];
				ptga[2] = pbits[1];
				ptga[3] = pbits[0];

				ptga += 4;
				pbits += 4;
			}
			break;

		case B_CMYA32:
			bytescopied = width * 4;
			while (width--) {
				ptga[0] = 255 - pbits[2];
				ptga[1] = 255 - pbits[1];
				ptga[2] = 255 - pbits[0];
				ptga[3] = pbits[3];

				ptga += 4;
				pbits += 4;
			}
			break;

		case B_RGB32:
		case B_RGB24:
			bytescopied = width * 3;
			while (width--) {
				memcpy(ptga, pbits, 3);

				ptga += 3;
				pbits += bitsBytesPerPixel;
			}
			break;

		case B_CMYK32:
		{
			int32 comp;
			bytescopied = width * 3;
			while (width--) {
				comp = 255 - pbits[2] - pbits[3];
				ptga[0] = (comp < 0) ? 0 : comp;

				comp = 255 - pbits[1] - pbits[3];
				ptga[1] = (comp < 0) ? 0 : comp;

				comp = 255 - pbits[0] - pbits[3];
				ptga[2] = (comp < 0) ? 0 : comp;

				ptga += 3;
				pbits += 4;
			}
			break;
		}

		case B_CMY32:
		case B_CMY24:
			bytescopied = width * 3;
			while (width--) {
				ptga[0] = 255 - pbits[2];
				ptga[1] = 255 - pbits[1];
				ptga[2] = 255 - pbits[0];

				ptga += 3;
				pbits += bitsBytesPerPixel;
			}
			break;

		case B_RGB16:
		case B_RGB16_BIG:
		{
			// Expand to 24 bit because the TGA format handles
			// 16 bit images differently than the Be Image Format
			// which would cause a loss in quality
			uint16 val;
			bytescopied = width * 3;
			while (width--) {
				if (fromspace == B_RGB16)
					val = pbits[0] + (pbits[1] << 8);
				else
					val = pbits[1] + (pbits[0] << 8);

				ptga[0] =
					((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
				ptga[1] =
					((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9);
				ptga[2] =
					((val & 0xf800) >> 8) | ((val & 0xf800) >> 13);

				ptga += 3;
				pbits += 2;
			}
			break;
		}

		case B_RGBA15:
			bytescopied = width * 2;
			memcpy(ptga, pbits, bytescopied);
			break;

		case B_RGBA15_BIG:
			bytescopied = width * 2;
			while (width--) {
				ptga[0] = pbits[1];
				ptga[1] = pbits[0];

				ptga += 2;
				pbits += 2;
			}
			break;

		case B_RGB15:
			bytescopied = width * 2;
			while (width--) {
				ptga[0] = pbits[0];
				ptga[1] = pbits[1] | 0x80;
					// alpha bit is always 1

				ptga += 2;
				pbits += 2;
			}
			break;

		case B_RGB15_BIG:
			bytescopied = width * 2;
			while (width--) {
				ptga[0] = pbits[1];
				ptga[1] = pbits[0] | 0x80;
					// alpha bit is always 1

				ptga += 2;
				pbits += 2;
			}
			break;

		case B_RGB32_BIG:
			bytescopied = width * 3;
			while (width--) {
				ptga[0] = pbits[3];
				ptga[1] = pbits[2];
				ptga[2] = pbits[1];

				ptga += 3;
				pbits += 4;
			}
			break;

		case B_RGB24_BIG:
			bytescopied = width * 3;
			while (width--) {
				ptga[0] = pbits[2];
				ptga[1] = pbits[1];
				ptga[2] = pbits[0];

				ptga += 3;
				pbits += 3;
			}
			break;

		case B_CMAP8:
		{
			rgb_color c;
			bytescopied = width * 3;
			while (width--) {
				c = pmap->color_list[pbits[0]];
				ptga[0] = c.blue;
				ptga[1] = c.green;
				ptga[2] = c.red;

				ptga += 3;
				pbits++;
			}
			break;
		}

		case B_GRAY8:
			// NOTE: this code assumes that the
			// destination TGA color space is either
			// 8 bit indexed color or 8 bit grayscale
			bytescopied = width;
			memcpy(ptga, pbits, bytescopied);
			break;

		default:
			bytescopied = B_ERROR;
			break;
	} // switch (fromspace)

	return bytescopied;
}

// create a TGA RLE packet for pixel and copy the
// packet header and pixel data to ptga
status_t
copy_rle_packet(uint8 *ptga, uint32 pixel, uint8 count,
	color_space fromspace, const color_map *pmap,
	int32 bitsBytesPerPixel)
{
	// copy packet header
	// (made of type and count)
	uint8 packethead = (count - 1) | 0x80;
	ptga[0] = packethead;
	ptga++;

	return pix_bits_to_tga(reinterpret_cast<uint8 *> (&pixel),
		ptga, fromspace, 1, pmap, bitsBytesPerPixel) + 1;
}

// create a TGA raw packet for pixel and copy the
// packet header and pixel data to ptga
status_t
copy_raw_packet(uint8 *ptga, uint8 *praw, uint8 count,
	color_space fromspace, const color_map *pmap,
	int32 bitsBytesPerPixel)
{
	// copy packet header
	// (made of type and count)
	uint8 packethead = count - 1;
	ptga[0] = packethead;
	ptga++;

	return pix_bits_to_tga(praw, ptga, fromspace,
		count, pmap, bitsBytesPerPixel) + 1;
}

// convert a row of pixel data from pbits to a
// row of pixel data in the TGA format using
// Run Length Encoding
status_t
pix_bits_to_tgarle(uint8 *pbits, uint8 *ptga, color_space fromspace,
	uint16 width, const color_map *pmap, int32 bitsBytesPerPixel)
{
	if (width == 0)
		return B_ERROR;

	uint32 current = 0, next = 0, aftnext = 0;
	uint16 nread = 0;
	status_t result, bytescopied = 0;
	uint8 *prawbuf, *praw;
	prawbuf = new(std::nothrow) uint8[bitsBytesPerPixel * 128];
	praw = prawbuf;
	if (!prawbuf)
		return B_ERROR;

	uint8 rlecount = 1, rawcount = 0;
	bool bJustWroteRLE = false;

	memcpy(&current, pbits, bitsBytesPerPixel);
	pbits += bitsBytesPerPixel;
	if (width == 1) {
		result = copy_raw_packet(ptga,
			reinterpret_cast<uint8 *> (&current), 1,
			fromspace, pmap, bitsBytesPerPixel);

		ptga += result;
		bytescopied += result;
		nread++;
			// don't enter the while loop

	} else {
		memcpy(&next, pbits, bitsBytesPerPixel);
		pbits += bitsBytesPerPixel;
		nread++;
	}

	while (nread < width) {

		if (nread < width - 1) {
			memcpy(&aftnext, pbits, bitsBytesPerPixel);
			pbits += bitsBytesPerPixel;
		}
		nread++;

		// RLE Packet Creation
		if (current == next && !bJustWroteRLE) {
			rlecount++;

			if (next != aftnext || nread == width || rlecount == 128) {
				result = copy_rle_packet(ptga, current, rlecount,
					fromspace, pmap, bitsBytesPerPixel);

				ptga += result;
				bytescopied += result;
				rlecount = 1;
				bJustWroteRLE = true;
			}

		// RAW Packet Creation
		} else {

			if (!bJustWroteRLE) {
				// output the current pixel only if
				// it was not just written out in an RLE packet
				rawcount++;
				memcpy(praw, &current, bitsBytesPerPixel);
				praw += bitsBytesPerPixel;
			}

			if (nread == width) {
				// if in the last iteration of the loop,
				// "next" will be the last pixel in the row,
				// and will need to be written out for this
				// special case

				if (rawcount == 128) {
					result = copy_raw_packet(ptga, prawbuf, rawcount,
						fromspace, pmap, bitsBytesPerPixel);

					ptga += result;
					bytescopied += result;
					praw = prawbuf;
					rawcount = 0;
				}

				rawcount++;
				memcpy(praw, &next, bitsBytesPerPixel);
				praw += bitsBytesPerPixel;
			}

			if ((!bJustWroteRLE && next == aftnext) ||
				nread == width || rawcount == 128) {
				result = copy_raw_packet(ptga, prawbuf, rawcount,
					fromspace, pmap, bitsBytesPerPixel);

				ptga += result;
				bytescopied += result;
				praw = prawbuf;
				rawcount = 0;
			}

			bJustWroteRLE = false;
		}

		current = next;
		next = aftnext;
	}

	delete[] prawbuf;
	prawbuf = NULL;

	return bytescopied;
}

// ---------------------------------------------------------------
// translate_from_bits_to_tgatc
//
// Converts various varieties of the Be Bitmap format ('bits') to
// the TGA True Color format (RLE or uncompressed)
//
// Preconditions:
//
// Parameters:	inSource,	contains the bits data to convert
//
//				outDestination,	where the TGA data will be written
//
//				fromspace,	the format of the data in inSource
//
//				imagespec,	info about width / height / etc. of
//							the image
//
//				brle,	output using RLE if true, uncompressed
//						if false
//
//
// Postconditions:
//
// Returns: B_ERROR,	if memory couldn't be allocated or another
//						error occured
//
// B_OK,	if no errors occurred
// ---------------------------------------------------------------
status_t
translate_from_bits_to_tgatc(BPositionIO *inSource,
	BPositionIO *outDestination, color_space fromspace,
	TGAImageSpec &imagespec, bool brle)
{
	int32 bitsBytesPerPixel = 0;
	switch (fromspace) {
		case B_RGB32:
		case B_RGB32_BIG:
		case B_RGBA32:
		case B_RGBA32_BIG:
		case B_CMY32:
		case B_CMYA32:
		case B_CMYK32:
			bitsBytesPerPixel = 4;
			break;

		case B_RGB24:
		case B_RGB24_BIG:
		case B_CMY24:
			bitsBytesPerPixel = 3;
			break;

		case B_RGB16:
		case B_RGB16_BIG:
		case B_RGBA15:
		case B_RGBA15_BIG:
		case B_RGB15:
		case B_RGB15_BIG:
			bitsBytesPerPixel = 2;
			break;

		case B_CMAP8:
		case B_GRAY8:
			bitsBytesPerPixel = 1;
			break;

		default:
			return B_ERROR;
	}
	int32 bitsRowBytes = imagespec.width * bitsBytesPerPixel;
	uint8 tgaBytesPerPixel = (imagespec.depth / 8) +
		((imagespec.depth % 8) ? 1 : 0);
	int32 tgaRowBytes = (imagespec.width * tgaBytesPerPixel) +
		(imagespec.width / 2);
	uint32 tgapixrow = 0;
	uint8 *tgaRowData = new(std::nothrow) uint8[tgaRowBytes];
	if (!tgaRowData)
		return B_ERROR;
	uint8 *bitsRowData = new(std::nothrow) uint8[bitsRowBytes];
	if (!bitsRowData) {
		delete[] tgaRowData;
		tgaRowData = NULL;
		return B_ERROR;
	}

	// conversion function pointer, points to either
	// RLE or normal TGA conversion function
	status_t (*convert_to_tga)(uint8 *pbits, uint8 *ptga,
		color_space fromspace, uint16 width, const color_map *pmap,
		int32 bitsBytesPerPixel);

	if (brle)
		convert_to_tga = pix_bits_to_tgarle;
	else
		convert_to_tga = pix_bits_to_tga;

	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
	const color_map *pmap = NULL;
	if (fromspace == B_CMAP8) {
		pmap = system_colors();
		if (!pmap) {
			delete[] tgaRowData;
			delete[] bitsRowData;
			return B_ERROR;
		}
	}
	while (rd == bitsRowBytes) {
		status_t bytescopied;
		bytescopied = convert_to_tga(bitsRowData, tgaRowData, fromspace,
			imagespec.width, pmap, bitsBytesPerPixel);

		outDestination->Write(tgaRowData, bytescopied);
		tgapixrow++;
		// if I've read all of the pixel data, break
		// out of the loop so I don't try to read
		// non-pixel data
		if (tgapixrow == imagespec.height)
			break;

		rd = inSource->Read(bitsRowData, bitsRowBytes);
	} // while (rd == bitsRowBytes)

	delete[] bitsRowData;
	bitsRowData = NULL;
	delete[] tgaRowData;
	tgaRowData = NULL;

	return B_OK;
}

// ---------------------------------------------------------------
// translate_from_bits1_to_tgabw
//
// Converts 1-bit Be Bitmaps ('bits') to the
// black and white (8-bit grayscale) TGA format
//
// Preconditions:
//
// Parameters:	inSource,	contains the bits data to convert
//
//				outDestination,	where the TGA data will be written
//
//				bitsRowBytes,	number of bytes in one row of
//								bits data
//
//				imagespec,	info about width / height / etc. of
//							the image
//
//				brle,	output using RLE if true, uncompressed
//						if false
//
//
// Postconditions:
//
// Returns: B_ERROR,	if memory couldn't be allocated or another
//						error occured
//
// B_OK,	if no errors occurred
// ---------------------------------------------------------------
status_t
translate_from_bits1_to_tgabw(BPositionIO *inSource,
	BPositionIO *outDestination, int32 bitsRowBytes,
	TGAImageSpec &imagespec, bool brle)
{
	uint8 tgaBytesPerPixel = 1;
	int32 tgaRowBytes = (imagespec.width * tgaBytesPerPixel) +
		(imagespec.width / 2);
	uint32 tgapixrow = 0;
	uint8 *tgaRowData = new(std::nothrow) uint8[tgaRowBytes];
	if (!tgaRowData)
		return B_ERROR;

	uint8 *medRowData = new(std::nothrow) uint8[imagespec.width];
	if (!medRowData) {
		delete[] tgaRowData;
		tgaRowData = NULL;
		return B_ERROR;
	}
	uint8 *bitsRowData = new(std::nothrow) uint8[bitsRowBytes];
	if (!bitsRowData) {
		delete[] medRowData;
		medRowData = NULL;
		delete[] tgaRowData;
		tgaRowData = NULL;
		return B_ERROR;
	}

	// conversion function pointer, points to either
	// RLE or normal TGA conversion function
	status_t (*convert_to_tga)(uint8 *pbits, uint8 *ptga,
		color_space fromspace, uint16 width, const color_map *pmap,
		int32 bitsBytesPerPixel);

	if (brle)
		convert_to_tga = pix_bits_to_tgarle;
	else
		convert_to_tga = pix_bits_to_tga;

	ssize_t rd = inSource->Read(bitsRowData, bitsRowBytes);
	while (rd == bitsRowBytes) {
		uint32 tgapixcol = 0;
		for (int32 i = 0; (tgapixcol < imagespec.width) &&
			(i < bitsRowBytes); i++) {
			// process each byte in the row
			uint8 pixels = bitsRowData[i];
			for (uint8 compbit = 128; (tgapixcol < imagespec.width) &&
				compbit; compbit >>= 1) {
				// for each bit in the current byte, convert to a TGA palette
				// index and store that in the tgaRowData
				if (pixels & compbit)
					// black
					medRowData[tgapixcol] = 0;
				else
					// white
					medRowData[tgapixcol] = 255;
				tgapixcol++;
			}
		}

		status_t bytescopied;
		bytescopied = convert_to_tga(medRowData, tgaRowData, B_GRAY8,
			imagespec.width, NULL, 1);

		outDestination->Write(tgaRowData, bytescopied);
		tgapixrow++;
		// if I've read all of the pixel data, break
		// out of the loop so I don't try to read
		// non-pixel data
		if (tgapixrow == imagespec.height)
			break;

		rd = inSource->Read(bitsRowData, bitsRowBytes);
	} // while (rd == bitsRowBytes)

	delete[] bitsRowData;
	bitsRowData = NULL;
	delete[] medRowData;
	medRowData = NULL;
	delete[] tgaRowData;
	tgaRowData = NULL;

	return B_OK;
}

// ---------------------------------------------------------------
// write_tga_headers
//
// Writes the TGA headers to outDestination.
//
// Preconditions:
//
// Parameters:	outDestination,	where the headers are written to
//
//				fileheader, TGA file header
//
//				mapspec,	color map information
//
//				imagespec,	width / height / etc. info
//
//
// Postconditions:
//
// Returns: B_ERROR, if something went wrong
//
// B_OK, if there were no problems writing out the headers
// ---------------------------------------------------------------
status_t
write_tga_headers(BPositionIO *outDestination, TGAFileHeader &fileheader,
	TGAColorMapSpec &mapspec, TGAImageSpec &imagespec)
{
	uint8 tgaheaders[TGA_HEADERS_SIZE];

	// Convert host format headers to Little Endian (Intel) byte order
	TGAFileHeader outFileheader;
	outFileheader.idlength = fileheader.idlength;
	outFileheader.colormaptype = fileheader.colormaptype;
	outFileheader.imagetype = fileheader.imagetype;

	TGAColorMapSpec outMapspec;
	outMapspec.firstentry = B_HOST_TO_LENDIAN_INT16(mapspec.firstentry);
	outMapspec.length = B_HOST_TO_LENDIAN_INT16(mapspec.length);
	outMapspec.entrysize = mapspec.entrysize;

	TGAImageSpec outImagespec;
	outImagespec.xorigin = B_HOST_TO_LENDIAN_INT16(imagespec.xorigin);
	outImagespec.yorigin = B_HOST_TO_LENDIAN_INT16(imagespec.yorigin);
	outImagespec.width = B_HOST_TO_LENDIAN_INT16(imagespec.width);
	outImagespec.height = B_HOST_TO_LENDIAN_INT16(imagespec.height);
	outImagespec.depth = imagespec.depth;
	outImagespec.descriptor = imagespec.descriptor;

	// Copy TGA headers to buffer to be written out
	// all at once
	tgaheaders[0] = outFileheader.idlength;
	tgaheaders[1] = outFileheader.colormaptype;
	tgaheaders[2] = outFileheader.imagetype;

	memcpy(tgaheaders + 3, &outMapspec.firstentry, 2);
	memcpy(tgaheaders + 5, &outMapspec.length, 2);
	tgaheaders[7] = outMapspec.entrysize;

	memcpy(tgaheaders + 8, &outImagespec.xorigin, 2);
	memcpy(tgaheaders + 10, &outImagespec.yorigin, 2);
	memcpy(tgaheaders + 12, &outImagespec.width, 2);
	memcpy(tgaheaders + 14, &outImagespec.height, 2);
	tgaheaders[16] = outImagespec.depth;
	tgaheaders[17] = outImagespec.descriptor;

	ssize_t written;
	written = outDestination->Write(tgaheaders, TGA_HEADERS_SIZE);

	if (written == TGA_HEADERS_SIZE)
		return B_OK;
	else
		return B_ERROR;
}

// ---------------------------------------------------------------
// write_tga_footer
//
// Writes the TGA footer.  This information is contant in this
// code because this translator does not output the developer
// information section of the TGA format.
//
// Preconditions:
//
// Parameters:	outDestination,	where the headers are written to
//
//
// Postconditions:
//
// Returns: B_ERROR, if something went wrong
//
// B_OK, if there were no problems writing out the headers
// ---------------------------------------------------------------
status_t
write_tga_footer(BPositionIO *outDestination)
{
	const int32 kfootersize = 26;
	uint8 footer[kfootersize];

	memset(footer, 0, 8);
		// set the Extension Area Offset and Developer
		// Area Offset to zero (as they are not present)

	memcpy(footer + 8, "TRUEVISION-XFILE.", 18);
		// copy the string including the '.' and the '\0'

	ssize_t written;
	written = outDestination->Write(footer, kfootersize);
	if (written == kfootersize)
		return B_OK;
	else
		return B_ERROR;
}

// ---------------------------------------------------------------
// translate_from_bits
//
// Convert the data in inSource from the Be Bitmap format ('bits')
// to the format specified in outType (either bits or TGA).
//
// Preconditions:
//
// Parameters:	inSource,	the bits data to translate
//
// 				amtread,	the amount of data already read from
//							inSource
//
//				read,		pointer to the data already read from
//							inSource
//
//
//				outType,	the type of data to convert to
//
//				outDestination,	where the output is written to
//
// Postconditions:
//
// Returns: B_NO_TRANSLATOR,	if the data is not in a supported
//								format
//
// B_ERROR, if there was an error allocating memory or some other
//			error
//
// B_OK, if successfully translated the data from the bits format
// ---------------------------------------------------------------
status_t
TGATranslator::translate_from_bits(BPositionIO *inSource, uint32 outType,
	BPositionIO *outDestination)
{
	TranslatorBitmap bitsHeader;
	bool bheaderonly = false, bdataonly = false, brle;
	brle = fSettings->SetGetBool(TGA_SETTING_RLE);

	status_t result;
	result = identify_bits_header(inSource, NULL, &bitsHeader);
	if (result != B_OK)
		return result;

	// Translate B_TRANSLATOR_BITMAP to B_TGA_FORMAT
	if (outType == B_TGA_FORMAT) {
		// Set up TGA header
		TGAFileHeader fileheader;
		fileheader.idlength = 0;
		fileheader.colormaptype = TGA_NO_COLORMAP;
		fileheader.imagetype = 0;

		TGAColorMapSpec mapspec;
		mapspec.firstentry = 0;
		mapspec.length = 0;
		mapspec.entrysize = 0;

		TGAImageSpec imagespec;
		imagespec.xorigin = 0;
		imagespec.yorigin = 0;
		imagespec.width = static_cast<uint16> (bitsHeader.bounds.Width() + 1);
		imagespec.height = static_cast<uint16> (bitsHeader.bounds.Height() + 1);
		imagespec.depth = 0;
		imagespec.descriptor = TGA_ORIGIN_VERT_BIT;

		// determine fileSize / imagesize
		switch (bitsHeader.colors) {

			// Output to 32-bit True Color TGA (8 bits alpha)
			case B_RGBA32:
			case B_RGBA32_BIG:
			case B_CMYA32:
				if (brle)
					fileheader.imagetype = TGA_RLE_TRUECOLOR;
				else
					fileheader.imagetype = TGA_NOCOMP_TRUECOLOR;
				imagespec.depth = 32;
				imagespec.descriptor |= 8;
					// 8 bits of alpha
				break;

			// Output to 24-bit True Color TGA (no alpha)
			case B_RGB32:
			case B_RGB32_BIG:
			case B_RGB24:
			case B_RGB24_BIG:
			case B_CMYK32:
			case B_CMY32:
			case B_CMY24:
				if (brle)
					fileheader.imagetype = TGA_RLE_TRUECOLOR;
				else
					fileheader.imagetype = TGA_NOCOMP_TRUECOLOR;
				imagespec.depth = 24;
				break;

			// Output to 16-bit True Color TGA (no alpha)
			// (TGA doesn't see 16 bit images as Be does
			// so converting 16 bit Be Image to 16-bit TGA
			// image would result in loss of quality)
			case B_RGB16:
			case B_RGB16_BIG:
				if (brle)
					fileheader.imagetype = TGA_RLE_TRUECOLOR;
				else
					fileheader.imagetype = TGA_NOCOMP_TRUECOLOR;
				imagespec.depth = 24;
				break;

			// Output to 15-bit True Color TGA (1 bit alpha)
			case B_RGB15:
			case B_RGB15_BIG:
				if (brle)
					fileheader.imagetype = TGA_RLE_TRUECOLOR;
				else
					fileheader.imagetype = TGA_NOCOMP_TRUECOLOR;
				imagespec.depth = 16;
				imagespec.descriptor |= 1;
					// 1 bit of alpha (always opaque)
				break;

			// Output to 16-bit True Color TGA (1 bit alpha)
			case B_RGBA15:
			case B_RGBA15_BIG:
				if (brle)
					fileheader.imagetype = TGA_RLE_TRUECOLOR;
				else
					fileheader.imagetype = TGA_NOCOMP_TRUECOLOR;
				imagespec.depth = 16;
				imagespec.descriptor |= 1;
					// 1 bit of alpha
				break;

			// Output to 8-bit Color Mapped TGA 32 bits per color map entry
			case B_CMAP8:
				fileheader.colormaptype = TGA_COLORMAP;
				if (brle)
					fileheader.imagetype = TGA_RLE_COLORMAP;
				else
					fileheader.imagetype = TGA_NOCOMP_COLORMAP;
				mapspec.firstentry = 0;
				mapspec.length = 256;
				mapspec.entrysize = 32;
				imagespec.depth = 8;
				imagespec.descriptor |= 8;
					// the pixel values contain 8 bits of attribute data
				break;

			// Output to 8-bit Black and White TGA
			case B_GRAY8:
			case B_GRAY1:
				if (brle)
					fileheader.imagetype = TGA_RLE_BW;
				else
					fileheader.imagetype = TGA_NOCOMP_BW;
				imagespec.depth = 8;
				break;

			default:
				return B_NO_TRANSLATOR;
		}

		// write out the TGA headers
		if (bheaderonly || (!bheaderonly && !bdataonly)) {
			result = write_tga_headers(outDestination, fileheader,
				mapspec, imagespec);
			if (result != B_OK)
				return result;
		}
		if (bheaderonly)
			// if user only wants the header, bail out
			// before the data is written
			return result;

		// write out the TGA pixel data
		switch (bitsHeader.colors) {
			case B_RGB32:
			case B_RGB32_BIG:
			case B_RGBA32:
			case B_RGBA32_BIG:
			case B_RGB24:
			case B_RGB24_BIG:
			case B_RGB16:
			case B_RGB16_BIG:
			case B_RGB15:
			case B_RGB15_BIG:
			case B_RGBA15:
			case B_RGBA15_BIG:
			case B_CMYK32:
			case B_CMY32:
			case B_CMYA32:
			case B_CMY24:
				result = translate_from_bits_to_tgatc(inSource, outDestination,
					bitsHeader.colors, imagespec, brle);
				break;

			case B_CMAP8:
			{
				// write Be's system palette to the TGA file
				uint8 pal[1024];
				const color_map *pmap = system_colors();
				if (!pmap)
					return B_ERROR;
				for (int32 i = 0; i < 256; i++) {
					uint8 *palent = pal + (i * 4);
					rgb_color c = pmap->color_list[i];
					palent[0] = c.blue;
					palent[1] = c.green;
					palent[2] = c.red;
					palent[3] = c.alpha;
				}
				if (outDestination->Write(pal, 1024) != 1024)
					return B_ERROR;

				result = translate_from_bits_to_tgatc(inSource, outDestination,
					B_GRAY8, imagespec, brle);
				break;
			}

			case B_GRAY8:
				result = translate_from_bits_to_tgatc(inSource, outDestination,
					B_GRAY8, imagespec, brle);
				break;

			case B_GRAY1:
				result = translate_from_bits1_to_tgabw(inSource, outDestination,
					bitsHeader.rowBytes, imagespec, brle);
				break;

			default:
				result = B_NO_TRANSLATOR;
				break;
		}

		if (result == B_OK)
			result = write_tga_footer(outDestination);

		return result;

	} else
		return B_NO_TRANSLATOR;
}

// convert a row of uncompressed, non-color mapped
// TGA pixels from ptga to pbits
status_t
pix_tganm_to_bits(uint8 *pbits, uint8 *ptga,
	uint16 width, uint8 depth, uint8 tgaBytesPerPixel,
	uint8 nalpha)
{
	status_t result = B_OK;

	switch (depth) {
		case 32:
			if (nalpha == 8 && tgaBytesPerPixel == 4)
				memcpy(pbits, ptga, 4 * width);
			else if (nalpha == 8) {
				// copy the same 32-bit pixel over and over
				while (width--) {
					memcpy(pbits, ptga, 4);
					pbits += 4;
				}
			} else {
				while (width--) {
					memcpy(pbits, ptga, 3);

					pbits += 4;
					ptga += tgaBytesPerPixel;
				}
			}
			break;

		case 24:
			while (width--) {
				memcpy(pbits, ptga, 3);

				pbits += 4;
				ptga += tgaBytesPerPixel;
			}
			break;

		case 16:
		{
			uint16 val;
			if (nalpha == 1) {
				while (width--) {
					val = ptga[0] + (ptga[1] << 8);
					pbits[0] =
						((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
					pbits[1] =
						((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
					pbits[2] =
						((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
					pbits[3] = (val & 0x8000) ? 255 : 0;

					pbits += 4;
					ptga += tgaBytesPerPixel;
				}
			} else {
				while (width--) {
					val = ptga[0] + (ptga[1] << 8);
					pbits[0] =
						((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
					pbits[1] =
						((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
					pbits[2] =
						((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);

					pbits += 4;
					ptga += tgaBytesPerPixel;
				}
			}
			break;
		}

		case 15:
		{
			uint16 val;
			while (width--) {
				val = ptga[0] + (ptga[1] << 8);
				pbits[0] =
					((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
				pbits[1] =
					((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
				pbits[2] =
					((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);

				pbits += 4;
				ptga += tgaBytesPerPixel;
			}
			break;
		}

		case 8:
			while (width--) {
				memset(pbits, ptga[0], 3);

				pbits += 4;
				ptga += tgaBytesPerPixel;
			}
			break;

		default:
			result = B_ERROR;
			break;
	}

	return result;
}

// ---------------------------------------------------------------
// translate_from_tganm_to_bits
//
// Translates a uncompressed, non-palette TGA from inSource
// to the B_RGB32 or B_RGBA32 bits format.
//
// Preconditions:
//
// Parameters: inSource,	the TGA data to be translated
//
// outDestination,	where the bits data will be written to
//
// filehead, image type info
//
// mapspec, color map info
//
// imagespec, width / height info
//
//
//
// Postconditions:
//
// Returns: B_ERROR, if there is an error allocating memory
//
// B_OK, if all went well
// ---------------------------------------------------------------
status_t
TGATranslator::translate_from_tganm_to_bits(BPositionIO *inSource,
	BPositionIO *outDestination, TGAFileHeader &filehead,
	TGAColorMapSpec &mapspec, TGAImageSpec &imagespec)
{
	bool bvflip;
	if (imagespec.descriptor & TGA_ORIGIN_VERT_BIT)
		bvflip = false;
	else
		bvflip = true;
	uint8 nalpha = tga_alphabits(filehead, mapspec, imagespec);
	int32 bitsRowBytes = imagespec.width * 4;
	uint8 tgaBytesPerPixel = (imagespec.depth / 8) +
		((imagespec.depth % 8) ? 1 : 0);
	int32 tgaRowBytes = (imagespec.width * tgaBytesPerPixel);
	uint32 tgapixrow = 0;

	// Setup outDestination so that it can be written to
	// from the end of the file to the beginning instead of
	// the other way around
	off_t bitsFileSize = (bitsRowBytes * imagespec.height) +
		sizeof(TranslatorBitmap);
	if (outDestination->SetSize(bitsFileSize) != B_OK)
		// This call should work for BFile and BMallocIO objects,
		// but may not work for other BPositionIO based types
		return B_ERROR;
	off_t bitsoffset = (imagespec.height - 1) * bitsRowBytes;
	if (bvflip)
		outDestination->Seek(bitsoffset, SEEK_CUR);

	// allocate row buffers
	uint8 *tgaRowData = new(std::nothrow) uint8[tgaRowBytes];
	if (!tgaRowData)
		return B_ERROR;
	uint8 *bitsRowData = new(std::nothrow) uint8[bitsRowBytes];
	if (!bitsRowData) {
		delete[] tgaRowData;
		tgaRowData = NULL;
		return B_ERROR;
	}

	// perform the actual translation
	memset(bitsRowData, 0xff, bitsRowBytes);
	ssize_t rd = inSource->Read(tgaRowData, tgaRowBytes);
	while (rd == tgaRowBytes) {
		pix_tganm_to_bits(bitsRowData, tgaRowData,
			imagespec.width, imagespec.depth,
			tgaBytesPerPixel, nalpha);

		outDestination->Write(bitsRowData, bitsRowBytes);
		tgapixrow++;
		// if I've read all of the pixel data, break
		// out of the loop so I don't try to read
		// non-pixel data
		if (tgapixrow == imagespec.height)
			break;

		if (bvflip)
			outDestination->Seek(-(bitsRowBytes * 2), SEEK_CUR);
		rd = inSource->Read(tgaRowData, tgaRowBytes);
	}

	delete[] tgaRowData;
	tgaRowData = NULL;
	delete[] bitsRowData;
	bitsRowData = NULL;

	return B_OK;
}

// ---------------------------------------------------------------
// translate_from_tganmrle_to_bits
//
// Convert non color map, RLE TGA to Be bitmap format
// and write results to outDestination
//
// Preconditions:
//
// Parameters: inSource,	the TGA data to be translated
//
// outDestination,	where the bits data will be written to
//
// filehead, image type info
//
// mapspec, color map info
//
// imagespec, width / height info
//
//
//
// Postconditions:
//
// Returns: B_ERROR, if there is an error allocating memory
//
// B_OK, if all went well
// ---------------------------------------------------------------
status_t
TGATranslator::translate_from_tganmrle_to_bits(BPositionIO *inSource,
	BPositionIO *outDestination, TGAFileHeader &filehead,
	TGAColorMapSpec &mapspec, TGAImageSpec &imagespec)
{
	status_t result = B_OK;

	bool bvflip;
	if (imagespec.descriptor & TGA_ORIGIN_VERT_BIT)
		bvflip = false;
	else
		bvflip = true;
	uint8 nalpha = tga_alphabits(filehead, mapspec, imagespec);
	int32 bitsRowBytes = imagespec.width * 4;
	uint8 tgaBytesPerPixel = (imagespec.depth / 8) +
		((imagespec.depth % 8) ? 1 : 0);
	uint16 tgapixrow = 0, tgapixcol = 0;

	// Setup outDestination so that it can be written to
	// from the end of the file to the beginning instead of
	// the other way around
	off_t bitsFileSize = (bitsRowBytes * imagespec.height) +
		sizeof(TranslatorBitmap);
	if (outDestination->SetSize(bitsFileSize) != B_OK)
		// This call should work for BFile and BMallocIO objects,
		// but may not work for other BPositionIO based types
		return B_ERROR;
	off_t bitsoffset = (imagespec.height - 1) * bitsRowBytes;
	if (bvflip)
		outDestination->Seek(bitsoffset, SEEK_CUR);

	// allocate row buffers
	uint8 *bitsRowData = new(std::nothrow) uint8[bitsRowBytes];
	if (!bitsRowData)
		return B_ERROR;

	// perform the actual translation
	memset(bitsRowData, 0xff, bitsRowBytes);
	uint8 *pbitspixel = bitsRowData;
	uint8 packethead;
	StreamBuffer sbuf(inSource, TGA_STREAM_BUFFER_SIZE);
	ssize_t rd = 0;
	if (sbuf.InitCheck() == B_OK)
		rd = sbuf.Read(&packethead, 1);
	while (rd == 1) {
		// Run Length Packet
		if (packethead & TGA_RLE_PACKET_TYPE_BIT) {
			uint8 tgapixel[4], rlecount;
			rlecount = (packethead & ~TGA_RLE_PACKET_TYPE_BIT) + 1;
			if (tgapixcol + rlecount > imagespec.width) {
				result = B_NO_TRANSLATOR;
				break;
			}
			rd = sbuf.Read(tgapixel, tgaBytesPerPixel);
			if (rd == tgaBytesPerPixel) {
				pix_tganm_to_bits(pbitspixel, tgapixel,
					rlecount, imagespec.depth, 0, nalpha);

				pbitspixel += 4 * rlecount;
				tgapixcol += rlecount;
			} else {
				result = B_NO_TRANSLATOR;
				break; // error
			}

		// Raw Packet
		} else {
			uint8 tgaPixelBuf[512], rawcount;
			uint16 rawbytes;
			rawcount = (packethead & ~TGA_RLE_PACKET_TYPE_BIT) + 1;
			if (tgapixcol + rawcount > imagespec.width) {
				result = B_NO_TRANSLATOR;
				break;
			}
			rawbytes = tgaBytesPerPixel * rawcount;
			rd = sbuf.Read(tgaPixelBuf, rawbytes);
			if (rd == rawbytes) {
				pix_tganm_to_bits(pbitspixel, tgaPixelBuf,
					rawcount, imagespec.depth, tgaBytesPerPixel, nalpha);

				pbitspixel += 4 * rawcount;
				tgapixcol += rawcount;
			} else {
				result = B_NO_TRANSLATOR;
				break;
			}
		}

		if (tgapixcol == imagespec.width) {
			outDestination->Write(bitsRowData, bitsRowBytes);
			tgapixcol = 0;
			tgapixrow++;
			if (tgapixrow == imagespec.height)
				break;
			if (bvflip)
				outDestination->Seek(-(bitsRowBytes * 2), SEEK_CUR);
			pbitspixel = bitsRowData;
		}
		rd = sbuf.Read(&packethead, 1);
	}

	delete[] bitsRowData;
	bitsRowData = NULL;

	return result;
}

// convert a row of color mapped pixels to pbits
status_t
pix_tgam_to_bits(uint8 *pbits, uint8 *ptgaindices,
	uint16 width, uint8 depth, uint8 *pmap)
{
	status_t result = B_OK;
	uint8 *ptgapixel = NULL;

	switch (depth) {
		case 32:
			for (uint16 i = 0; i < width; i++) {
				ptgapixel = pmap +
					(ptgaindices[i] * 4);

				memcpy(pbits, ptgapixel, 4);

				pbits += 4;
			}
			break;

		case 24:
			for (uint16 i = 0; i < width; i++) {
				ptgapixel = pmap +
					(ptgaindices[i] * 3);

				memcpy(pbits, ptgapixel, 3);

				pbits += 4;
			}
			break;

		case 16:
			for (uint16 i = 0; i < width; i++) {
				uint16 val;

				ptgapixel = pmap +
					(ptgaindices[i] * 2);
				val = ptgapixel[0] + (ptgapixel[1] << 8);
				pbits[0] =
					((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
				pbits[1] =
					((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
				pbits[2] =
					((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);
				pbits[3] = (val & 0x8000) ? 255 : 0;

				pbits += 4;
			}
			break;

		case 15:
			for (uint16 i = 0; i < width; i++) {
				uint16 val;

				ptgapixel = pmap +
					(ptgaindices[i] * 2);
				val = ptgapixel[0] + (ptgapixel[1] << 8);
				pbits[0] =
					((val & 0x1f) << 3) | ((val & 0x1f) >> 2);
				pbits[1] =
					((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7);
				pbits[2] =
					((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12);

				pbits += 4;
			}
			break;

		default:
			result = B_ERROR;
			break;
	}

	return result;
}

// ---------------------------------------------------------------
// translate_from_tgam_to_bits
//
// Translates a paletted TGA from inSource to the bits format.
//
// Preconditions:
//
// Parameters: inSource,	the TGA data to be translated
//
// outDestination,	where the bits data will be written to
//
// mapspec, info about the color map (palette)
//
// imagespec, width / height info
//
// pmap, color palette
//
//
// Postconditions:
//
// Returns: B_ERROR, if there is an error allocating memory
//
// B_OK, if all went well
// ---------------------------------------------------------------
status_t
translate_from_tgam_to_bits(BPositionIO *inSource,
	BPositionIO *outDestination, TGAColorMapSpec &mapspec,
	TGAImageSpec &imagespec, uint8 *pmap)
{
	bool bvflip;
	if (imagespec.descriptor & TGA_ORIGIN_VERT_BIT)
		bvflip = false;
	else
		bvflip = true;

	int32 bitsRowBytes = imagespec.width * 4;
	uint8 tgaBytesPerPixel = (imagespec.depth / 8) +
		((imagespec.depth % 8) ? 1 : 0);
	int32 tgaRowBytes = (imagespec.width * tgaBytesPerPixel);
	uint32 tgapixrow = 0;

	// Setup outDestination so that it can be written to
	// from the end of the file to the beginning instead of
	// the other way around
	off_t bitsFileSize = (bitsRowBytes * imagespec.height) +
		sizeof(TranslatorBitmap);
	if (outDestination->SetSize(bitsFileSize) != B_OK)
		// This call should work for BFile and BMallocIO objects,
		// but may not work for other BPositionIO based types
		return B_ERROR;
	off_t bitsoffset = (imagespec.height - 1) * bitsRowBytes;
	if (bvflip)
		outDestination->Seek(bitsoffset, SEEK_CUR);

	// allocate row buffers
	uint8 *tgaRowData = new(std::nothrow) uint8[tgaRowBytes];
	if (!tgaRowData)
		return B_ERROR;
	uint8 *bitsRowData = new(std::nothrow) uint8[bitsRowBytes];
	if (!bitsRowData) {
		delete[] tgaRowData;
		tgaRowData = NULL;
		return B_ERROR;
	}

	// perform the actual translation
	memset(bitsRowData, 0xff, bitsRowBytes);
	ssize_t rd = inSource->Read(tgaRowData, tgaRowBytes);
	while (rd == tgaRowBytes) {
		pix_tgam_to_bits(bitsRowData, tgaRowData,
			imagespec.width, mapspec.entrysize, pmap);

		outDestination->Write(bitsRowData, bitsRowBytes);
		tgapixrow++;
		// if I've read all of the pixel data, break
		// out of the loop so I don't try to read
		// non-pixel data
		if (tgapixrow == imagespec.height)
			break;

		if (bvflip)
			outDestination->Seek(-(bitsRowBytes * 2), SEEK_CUR);
		rd = inSource->Read(tgaRowData, tgaRowBytes);
	}

	delete[] tgaRowData;
	tgaRowData = NULL;
	delete[] bitsRowData;
	bitsRowData = NULL;

	return B_OK;
}

// ---------------------------------------------------------------
// translate_from_tgamrle_to_bits
//
// Translates a color mapped or non color mapped RLE TGA from
// inSource to the bits format.
//
// Preconditions:
//
// Parameters: inSource,	the TGA data to be translated
//
// outDestination,	where the bits data will be written to
//
// filehead, image type info
//
// mapspec, info about the color map (palette)
//
// imagespec, width / height info
//
// pmap, color palette
//
//
// Postconditions:
//
// Returns: B_ERROR, if there is an error allocating memory
//
// B_OK, if all went well
// ---------------------------------------------------------------
status_t
TGATranslator::translate_from_tgamrle_to_bits(BPositionIO *inSource,
	BPositionIO *outDestination, TGAFileHeader &filehead,
	TGAColorMapSpec &mapspec, TGAImageSpec &imagespec, uint8 *pmap)
{
	status_t result = B_OK;

	bool bvflip;
	if (imagespec.descriptor & TGA_ORIGIN_VERT_BIT)
		bvflip = false;
	else
		bvflip = true;
	uint8 nalpha = tga_alphabits(filehead, mapspec, imagespec);
	int32 bitsRowBytes = imagespec.width * 4;
	uint8 tgaPalBytesPerPixel = (mapspec.entrysize / 8) +
		((mapspec.entrysize % 8) ? 1 : 0);
	uint8 tgaBytesPerPixel = (imagespec.depth / 8) +
		((imagespec.depth % 8) ? 1 : 0);
	uint16 tgapixrow = 0, tgapixcol = 0;

	// Setup outDestination so that it can be written to
	// from the end of the file to the beginning instead of
	// the other way around
	off_t bitsFileSize = (bitsRowBytes * imagespec.height) +
		sizeof(TranslatorBitmap);
	if (outDestination->SetSize(bitsFileSize) != B_OK)
		// This call should work for BFile and BMallocIO objects,
		// but may not work for other BPositionIO based types
		return B_ERROR;
	off_t bitsoffset = (imagespec.height - 1) * bitsRowBytes;
	if (bvflip)
		outDestination->Seek(bitsoffset, SEEK_CUR);

	// allocate row buffers
	uint8 *bitsRowData = new(std::nothrow) uint8[bitsRowBytes];
	if (!bitsRowData)
		return B_ERROR;

	// perform the actual translation
	memset(bitsRowData, 0xff, bitsRowBytes);
	uint8 *pbitspixel = bitsRowData;
	uint8 packethead;
	StreamBuffer sbuf(inSource, TGA_STREAM_BUFFER_SIZE);
	ssize_t rd = 0;
	if (sbuf.InitCheck() == B_OK)
		rd = sbuf.Read(&packethead, 1);
	while (rd == 1) {
		// Run Length Packet
		if (packethead & TGA_RLE_PACKET_TYPE_BIT) {
			uint8 tgaindex, rlecount;
			rlecount = (packethead & ~TGA_RLE_PACKET_TYPE_BIT) + 1;
			if (tgapixcol + rlecount > imagespec.width) {
				result = B_NO_TRANSLATOR;
				break;
			}
			rd = sbuf.Read(&tgaindex, 1);
			if (rd == tgaBytesPerPixel) {
				uint8 *ptgapixel;
				ptgapixel = pmap + (tgaindex * tgaPalBytesPerPixel);

				pix_tganm_to_bits(pbitspixel, ptgapixel, rlecount,
					mapspec.entrysize, 0, nalpha);

				pbitspixel += 4 * rlecount;
				tgapixcol += rlecount;
			} else {
				result = B_NO_TRANSLATOR;
				break; // error
			}

		// Raw Packet
		} else {
			uint8 tgaIndexBuf[128], rawcount;
			rawcount = (packethead & ~TGA_RLE_PACKET_TYPE_BIT) + 1;
			if (tgapixcol + rawcount > imagespec.width) {
				result = B_NO_TRANSLATOR;
				break;
			}
			rd = sbuf.Read(tgaIndexBuf, rawcount);
			if (rd == rawcount) {
				pix_tgam_to_bits(pbitspixel, tgaIndexBuf,
					rawcount, mapspec.entrysize, pmap);

				pbitspixel += 4 * rawcount;
				tgapixcol += rawcount;
			} else {
				result = B_NO_TRANSLATOR;
				break;
			}
		}

		if (tgapixcol == imagespec.width) {
			outDestination->Write(bitsRowData, bitsRowBytes);
			tgapixcol = 0;
			tgapixrow++;
			if (tgapixrow == imagespec.height)
				break;
			if (bvflip)
				outDestination->Seek(-(bitsRowBytes * 2), SEEK_CUR);
			pbitspixel = bitsRowData;
		}
		rd = sbuf.Read(&packethead, 1);
	}

	delete[] bitsRowData;
	bitsRowData = NULL;

	return result;
}

// ---------------------------------------------------------------
// translate_from_tga
//
// Convert the data in inSource from the TGA format
// to the format specified in outType (either bits or TGA).
//
// Preconditions:
//
// Parameters:	inSource,	the bits data to translate
//
// 				amtread,	the amount of data already read from
//							inSource
//
//				read,		pointer to the data already read from
//							inSource
//
//				outType,	the type of data to convert to
//
//				outDestination,	where the output is written to
//
// Postconditions:
//
// Returns: B_NO_TRANSLATOR,	if the data is not in a supported
//								format
//
// B_ERROR, if there was an error allocating memory or some other
//			error
//
// B_OK, if successfully translated the data from the bits format
// ---------------------------------------------------------------
status_t
TGATranslator::translate_from_tga(BPositionIO *inSource, uint32 outType,
	BPositionIO *outDestination)
{
	TGAFileHeader fileheader;
	TGAColorMapSpec mapspec;
	TGAImageSpec imagespec;
	bool bheaderonly = false, bdataonly = false;

	status_t result;
	result = identify_tga_header(inSource, NULL, &fileheader, &mapspec,
		&imagespec);
	if (result != B_OK)
		return result;

	// if the user wants to translate a TGA to a TGA, easy enough :)
	if (outType == B_TGA_FORMAT) {
		// write out the TGA headers
		if (bheaderonly || (!bheaderonly && !bdataonly)) {
			result = write_tga_headers(outDestination, fileheader,
				mapspec, imagespec);
			if (result != B_OK)
				return result;
		}
		if (bheaderonly)
			// if the user only wants the header,
			// bail before it is written
			return result;

		const int32 kbuflen = 1024;
		uint8 buf[kbuflen];
		ssize_t rd = inSource->Read(buf, kbuflen);
		while (rd > 0) {
			outDestination->Write(buf, rd);
			rd = inSource->Read(buf, kbuflen);
		}
		if (rd == 0)
			return B_OK;
		else
			return B_ERROR;

	// if translating a TGA to a Be Bitmap
	} else if (outType == B_TRANSLATOR_BITMAP) {
		TranslatorBitmap bitsHeader;
		bitsHeader.magic = B_TRANSLATOR_BITMAP;
		bitsHeader.bounds.left = 0;
		bitsHeader.bounds.top = 0;
		bitsHeader.bounds.right = imagespec.width - 1;
		bitsHeader.bounds.bottom = imagespec.height - 1;

		// skip over Image ID data (if present)
		if (fileheader.idlength > 0)
			inSource->Seek(fileheader.idlength, SEEK_CUR);

		// read in palette and/or skip non-TGA data
		uint8 *ptgapalette = NULL;
		if (fileheader.colormaptype == TGA_COLORMAP) {
			uint32 nentrybytes;
			nentrybytes = mapspec.entrysize / 8;
			if (mapspec.entrysize % 8)
				nentrybytes++;
			ptgapalette = new(std::nothrow) uint8[nentrybytes * mapspec.length];
			inSource->Read(ptgapalette, nentrybytes * mapspec.length);
		}

		bitsHeader.rowBytes = imagespec.width * 4;
		if (fileheader.imagetype != TGA_NOCOMP_BW &&
			fileheader.imagetype != TGA_RLE_BW &&
			tga_alphabits(fileheader, mapspec, imagespec))
			bitsHeader.colors = B_RGBA32;
		else
			bitsHeader.colors = B_RGB32;
		int32 datasize = bitsHeader.rowBytes * imagespec.height;
		bitsHeader.dataSize = datasize;

		// write out Be's Bitmap header
		if (bheaderonly || (!bheaderonly && !bdataonly)) {
			if (swap_data(B_UINT32_TYPE, &bitsHeader,
				sizeof(TranslatorBitmap), B_SWAP_HOST_TO_BENDIAN) != B_OK)
				return B_ERROR;
			outDestination->Write(&bitsHeader, sizeof(TranslatorBitmap));
		}
		if (bheaderonly)
			// if the user only wants the header,
			// bail before the data is written
			return B_OK;

		// write out the actual image data
		switch (fileheader.imagetype) {
			case TGA_NOCOMP_TRUECOLOR:
			case TGA_NOCOMP_BW:
				result = translate_from_tganm_to_bits(inSource,
					outDestination, fileheader, mapspec, imagespec);
				break;

			case TGA_NOCOMP_COLORMAP:
				result = translate_from_tgam_to_bits(inSource,
					outDestination, mapspec, imagespec, ptgapalette);
				break;

			case TGA_RLE_TRUECOLOR:
			case TGA_RLE_BW:
				result = translate_from_tganmrle_to_bits(inSource,
					outDestination, fileheader, mapspec, imagespec);
				break;

			case TGA_RLE_COLORMAP:
				result = translate_from_tgamrle_to_bits(inSource, outDestination,
					fileheader, mapspec, imagespec, ptgapalette);
				break;

			default:
				result = B_NO_TRANSLATOR;
				break;
		}

		delete[] ptgapalette;
		ptgapalette = NULL;

		return result;

	} else
		return B_NO_TRANSLATOR;
}

status_t
TGATranslator::DerivedTranslate(BPositionIO *inSource,
	const translator_info *inInfo, BMessage *ioExtension, uint32 outType,
	BPositionIO *outDestination, int32 baseType)
{
	if (baseType == 1)
		// if inSource is in bits format
		return translate_from_bits(inSource, outType, outDestination);
	else if (baseType == 0)
		// if inSource is NOT in bits format
		return translate_from_tga(inSource, outType, outDestination);
	else
		// if BaseTranslator did not properly identify the data as
		// bits or not bits
		return B_NO_TRANSLATOR;
}

BView *
TGATranslator::NewConfigView(TranslatorSettings *settings)
{
	return new(std::nothrow) TGAView(B_TRANSLATE("TGATranslator Settings"),
		B_WILL_DRAW, settings);
}