1/*****************************************************************************/
2// SGITranslator
3// Written by Stephan A��mus <stippi@yellowbites.com>
4// derived from GIMP SGI plugin by Michael Sweet
5//
6// SGIImage.cpp
7//
8// SGI image file format library routines.
9//
10// Formed into a class SGIImage, adopted to Be API and modified to use
11// BPositionIO, optimizations for buffered reading.
12//
13//
14// Copyright (c) 2003 Haiku Project
15// Portions Copyright 1997-1998 Michael Sweet (mike@easysw.com)
16//
17// Permission is hereby granted, free of charge, to any person obtaining a
18// copy of this software and associated documentation files (the "Software"),
19// to deal in the Software without restriction, including without limitation
20// the rights to use, copy, modify, merge, publish, distribute, sublicense,
21// and/or sell copies of the Software, and to permit persons to whom the
22// Software is furnished to do so, subject to the following conditions:
23//
24// The above copyright notice and this permission notice shall be included
25// in all copies or substantial portions of the Software.
26//
27// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33// DEALINGS IN THE SOFTWARE.
34/*****************************************************************************/
35
36#include <malloc.h>
37#include <stdio.h>
38#include <string.h>
39
40#include <ByteOrder.h>
41#include <DataIO.h>
42#include <TranslationErrors.h>
43
44#include "SGIImage.h"
45
46const char kSGICopyright[] = "" B_UTF8_COPYRIGHT " 1997-1998 Michael Sweet "
47	"<mike@easysw.com>";
48
49// constructor
50SGIImage::SGIImage()
51	: fStream(NULL),
52	  fMode(0),
53	  fBytesPerChannel(0),
54	  fCompression(0),
55	  fWidth(0),
56	  fHeight(0),
57	  fChannelCount(0),
58	  fFirstRowOffset(0),
59	  fNextRowOffset(0),
60	  fOffsetTable(NULL),
61	  fLengthTable(NULL),
62	  fARLERow(NULL),
63	  fARLEOffset(0),
64	  fARLELength(0)
65{
66}
67
68// destructor
69SGIImage::~SGIImage()
70{
71	Unset();
72}
73
74// InitCheck
75status_t
76SGIImage::InitCheck() const
77{
78	if (fStream)
79		return B_OK;
80	return B_NO_INIT;
81}
82
83// SetTo
84// open an SGI image file for reading
85//
86// stream	the input stream
87status_t
88SGIImage::SetTo(BPositionIO* stream)
89{
90	if (!stream)
91		return B_BAD_VALUE;
92
93	fStream = stream;
94	stream->Seek(0, SEEK_SET);
95
96	int16 magic = _ReadShort();
97	if (magic != SGI_MAGIC) {
98		fStream = NULL;
99		return B_NO_TRANSLATOR;
100	}
101
102	fMode = SGI_READ;
103
104	fCompression = _ReadChar();
105	fBytesPerChannel = _ReadChar();
106	_ReadShort();	// Dimensions
107	fWidth = _ReadShort();
108	fHeight = _ReadShort();
109	fChannelCount = _ReadShort();
110//	_ReadLong();	// Minimum pixel
111//	_ReadLong();	// Maximum pixel
112
113	if (fCompression) {
114		// this stream is compressed; read the scanline tables...
115
116		fStream->Seek(512, SEEK_SET);
117
118		fOffsetTable	= (int32**)calloc(fChannelCount, sizeof(int32*));
119		fOffsetTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
120		for (uint32 i = 1; i < fChannelCount; i++)
121			fOffsetTable[i] = fOffsetTable[0] + i * fHeight;
122
123		for (uint32 i = 0; i < fChannelCount; i++)
124			for (uint16 j = 0; j < fHeight; j++)
125				fOffsetTable[i][j] = _ReadLong();
126
127		fLengthTable	= (int32**)calloc(fChannelCount, sizeof(int32*));
128		fLengthTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
129
130		for (int32 i = 1; i < fChannelCount; i ++)
131			fLengthTable[i] = fLengthTable[0] + i * fHeight;
132
133		for (uint32 i = 0; i < fChannelCount; i++)
134			for (uint16 j = 0; j < fHeight; j++)
135				fLengthTable[i][j] = _ReadLong();
136
137	}
138	return B_OK;
139}
140
141// SetTo
142// open an SGI image file for writing
143//
144// stream			the output stream
145// width			number of pixels in a row
146// height			number of rows
147// channels			number of channels per pixel
148// bytesPerChannel	number of bytes per channel
149// compression		compression mode
150status_t
151SGIImage::SetTo(BPositionIO* stream,
152				uint16 width, uint16 height,
153				uint16 channels, uint32 bytesPerChannel,
154				uint32 compression)
155{
156	// sanity checks
157	if (!stream ||
158		width < 1 || height < 1 || channels < 1 ||
159		bytesPerChannel < 1 || bytesPerChannel > 2 ||
160		compression < SGI_COMP_NONE || compression > SGI_COMP_ARLE)
161		return B_BAD_VALUE;
162
163	fStream = stream;
164	fMode = SGI_WRITE;
165
166	_WriteShort(SGI_MAGIC);
167	_WriteChar((fCompression = compression) != 0);
168	_WriteChar(fBytesPerChannel = bytesPerChannel);
169	_WriteShort(3);		// Dimensions
170	_WriteShort(fWidth = width);
171	_WriteShort(fHeight = height);
172	_WriteShort(fChannelCount = channels);
173
174	if (fBytesPerChannel == 1) {
175		_WriteLong(0);		// Minimum pixel
176		_WriteLong(255);	// Maximum pixel
177	} else {
178		_WriteLong(-32768);	// Minimum pixel
179		_WriteLong(32767);	// Maximum pixel
180	}
181	_WriteLong(0);			// Reserved
182
183	char name[80];	// Name of file in image header
184	memset(name, 0, sizeof(name));
185	sprintf(name, "Haiku SGITranslator");
186	fStream->Write(name, sizeof(name));
187
188	// fill the rest of the image header with zeros
189	for (int32 i = 0; i < 102; i++)
190		_WriteLong(0);
191
192	switch (fCompression) {
193		case SGI_COMP_NONE : // No compression
194			// This file is uncompressed.  To avoid problems with
195			// sparse files, we need to write blank pixels for the
196			// entire image...
197
198/*			if (fBytesPerChannel == 1) {
199				for (int32 i = fWidth * fHeight * fChannelCount; i > 0; i --)
200					_WriteChar(0);
201			} else {
202				for (int32 i = fWidth * fHeight * fChannelCount; i > 0; i --)
203					_WriteShort(0);
204			}*/
205			break;
206
207		case SGI_COMP_ARLE: // Aggressive RLE
208			fARLERow	= (uint16*)calloc(fWidth, sizeof(uint16));
209			fARLEOffset = 0;
210			// FALL THROUGH
211		case SGI_COMP_RLE : // Run-Length Encoding
212			// This file is compressed; write the (blank) scanline tables...
213
214//			for (int32 i = 2 * fHeight * fChannelCount; i > 0; i--)
215//				_WriteLong(0);
216fStream->Seek(2 * fHeight * fChannelCount * sizeof(int32), SEEK_CUR);
217
218			fFirstRowOffset = fStream->Position();
219			fNextRowOffset  = fStream->Position();
220
221			// allocate and read offset table
222			fOffsetTable	= (int32**)calloc(fChannelCount, sizeof(int32*));
223			fOffsetTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
224
225			for (int32 i = 1; i < fChannelCount; i ++)
226				fOffsetTable[i] = fOffsetTable[0] + i * fHeight;
227
228			// allocate and read length table
229			fLengthTable	= (int32**)calloc(fChannelCount, sizeof(int32*));
230			fLengthTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
231
232			for (int32 i = 1; i < fChannelCount; i ++)
233				fLengthTable[i] = fLengthTable[0] + i * fHeight;
234			break;
235	}
236	return B_OK;
237}
238
239// Unset
240//
241// if in write mode, writes final information to the stream
242status_t
243SGIImage::Unset()
244{
245	status_t ret = InitCheck(); // return status
246	if (ret >= B_OK) {
247
248		if (fMode == SGI_WRITE && fCompression != SGI_COMP_NONE) {
249			// write the scanline offset table to the file...
250
251			fStream->Seek(512, SEEK_SET);
252
253/*			off_t* offset = fOffsetTable[0];
254			for (int32 i = fHeight * fChannelCount; i > 0; i--) {
255				if ((ret = _WriteLong(offset[0])) < B_OK)
256					break;
257				offset++;
258			}*/
259
260int32 size = fHeight * fChannelCount * sizeof(int32);
261swap_data(B_INT32_TYPE, fOffsetTable[0], size, B_SWAP_HOST_TO_BENDIAN);
262ret = fStream->Write(fOffsetTable[0], size);
263
264			if (ret >= B_OK) {
265
266/*				int32* length = fLengthTable[0];
267				for (int32 i = fHeight * fChannelCount; i > 0; i--) {
268					if ((ret = _WriteLong(length[0])) < B_OK)
269						break;
270					length++;
271				}*/
272
273swap_data(B_INT32_TYPE, fLengthTable[0], size, B_SWAP_HOST_TO_BENDIAN);
274ret = fStream->Write(fLengthTable[0], size);
275
276			}
277		}
278
279		if (fOffsetTable != NULL) {
280			free(fOffsetTable[0]);
281			free(fOffsetTable);
282			fOffsetTable = NULL;
283		}
284
285		if (fLengthTable != NULL) {
286			free(fLengthTable[0]);
287			free(fLengthTable);
288			fLengthTable = NULL;
289		}
290
291		if (fARLERow) {
292			free(fARLERow);
293			fARLERow = NULL;
294		}
295
296		fStream = NULL;
297	}
298	return ret;
299}
300
301// ReadRow
302//
303// reads a row of image data from the stream
304//
305// row			pointer to buffer (row of pixels) to read
306// y			index (line number) of this row
307// z			which channel to read
308status_t
309SGIImage::ReadRow(void* row, int32 y, int32 z)
310{
311	// sanitiy checks
312	if (row == NULL ||
313		y < 0 || y >= fHeight ||
314		z < 0 || z >= fChannelCount)
315		return B_BAD_VALUE;
316
317
318	status_t ret = B_ERROR;
319
320	switch (fCompression) {
321		case SGI_COMP_NONE: {
322			// seek to the image row
323			// optimize buffering by only seeking if necessary...
324
325			off_t offset = 512 + (y + z * fHeight) * fWidth * fBytesPerChannel;
326			fStream->Seek(offset, SEEK_SET);
327
328			uint32 bytes = fWidth * fBytesPerChannel;
329//printf("reading %ld bytes 8 Bit uncompressed row: %ld, channel: %ld\n", bytes, y, z);
330			ret = fStream->Read(row, bytes);
331
332			break;
333		}
334		case SGI_COMP_RLE: {
335			int32 offset = fOffsetTable[z][y];
336			int32 rleLength = fLengthTable[z][y];
337			fStream->Seek(offset, SEEK_SET);
338			uint8* rleBuffer = new uint8[rleLength];
339			fStream->Read(rleBuffer, rleLength);
340
341			if (fBytesPerChannel == 1) {
342//printf("reading 8 Bit RLE compressed row: %ld, channel: %ld\n", y, z);
343//				ret = _ReadRLE8((uint8*)row, fWidth);
344				ret = _ReadRLE8((uint8*)row, rleBuffer, fWidth);
345			} else {
346//printf("reading 16 Bit RLE compressed row: %ld, channel: %ld\n", y, z);
347//				ret = _ReadRLE16((uint16*)row, fWidth);
348				if ((ret = swap_data(B_INT16_TYPE, rleBuffer, rleLength, B_SWAP_BENDIAN_TO_HOST)) >= B_OK)
349					ret = _ReadRLE16((uint16*)row, (uint16*)rleBuffer, fWidth);
350			}
351			delete[] rleBuffer;
352			break;
353		}
354	}
355	return ret;
356}
357
358// WriteRow
359//
360// writes a row of image data to the stream
361//
362// row			pointer to buffer (row of pixels) to write
363// y			index (line number) of this row
364// z			which channel to write
365status_t
366SGIImage::WriteRow(void* row, int32 y, int32 z)
367{
368	// sanitiy checks
369	if (row == NULL ||
370		y < 0 || y >= fHeight ||
371		z < 0 || z >= fChannelCount)
372		return B_BAD_VALUE;
373
374	int32 x;		// x coordinate
375	int32 offset;	// stream offset
376
377	status_t ret = B_ERROR;
378
379	switch (fCompression) {
380		case SGI_COMP_NONE: {
381			// Seek to the image row
382
383			offset = 512 + (y + z * fHeight) * fWidth * fBytesPerChannel;
384			fStream->Seek(offset, SEEK_SET);
385
386			uint32 bytes = fWidth * fBytesPerChannel;
387//printf("writing %ld bytes %ld byte/channel uncompressed row: %ld, channel: %ld\n", bytes, fBytesPerChannel, y, z);
388			ret = fStream->Write(row, bytes);
389/*			if (fBytesPerChannel == 1) {
390				for (x = fWidth; x > 0; x--) {
391					_WriteChar(*row);
392					row++;
393				}
394			} else {
395				for (x = fWidth; x > 0; x--) {
396					_WriteShort(*row);
397					row++;
398				}
399			}*/
400			break;
401		}
402		case SGI_COMP_ARLE:
403			if (fOffsetTable[z][y] != 0)
404				return B_ERROR;
405
406			// First check the last row written...
407
408			if (fARLEOffset > 0) {
409				if (fBytesPerChannel == 1) {
410					uint8* arleRow = (uint8*)fARLERow;
411					uint8* src = (uint8*)row;
412					for (x = 0; x < fWidth; x++)
413						if (*src++ != *arleRow++)
414							break;
415				} else {
416					uint16* arleRow = (uint16*)fARLERow;
417					uint16* src = (uint16*)row;
418					for (x = 0; x < fWidth; x++)
419						if (*src++ != *arleRow++)
420							break;
421				}
422
423				if (x == fWidth) {
424					fOffsetTable[z][y] = fARLEOffset;
425					fLengthTable[z][y] = fARLELength;
426					return B_OK;
427				}
428			}
429
430			// If that didn't match, search all the previous rows...
431
432			fStream->Seek(fFirstRowOffset, SEEK_SET);
433
434			if (fBytesPerChannel == 1) {
435				do {
436					fARLEOffset = fStream->Position();
437
438					uint8* arleRow = (uint8*)fARLERow;
439					if ((fARLELength = _ReadRLE8(arleRow, fWidth)) < B_OK) {
440						x = 0;
441						break;
442					}
443
444					uint8* src = (uint8*)row;
445					for (x = 0; x < fWidth; x++)
446						if (*src++ != *arleRow++)
447							break;
448				} while (x < fWidth);
449			} else {
450				do {
451					fARLEOffset = fStream->Position();
452
453					uint16* arleRow = (uint16*)fARLERow;
454					if ((fARLELength = _ReadRLE16(arleRow, fWidth)) < B_OK) {
455						x = 0;
456						break;
457					}
458
459					uint16* src = (uint16*)row;
460					for (x = 0; x < fWidth; x++)
461						if (*src++ != *arleRow++)
462							break;
463				} while (x < fWidth);
464			}
465
466			if (x == fWidth) {
467				fOffsetTable[z][y] = fARLEOffset;
468				fLengthTable[z][y] = fARLELength;
469				return B_OK;
470			} else
471				fStream->Seek(0, SEEK_END);	// seek to end of stream
472			// FALL THROUGH!
473		case SGI_COMP_RLE :
474			if (fOffsetTable[z][y] != 0)
475				return B_ERROR;
476
477			offset = fOffsetTable[z][y] = fNextRowOffset;
478
479			if (offset != fStream->Position())
480				fStream->Seek(offset, SEEK_SET);
481
482//printf("writing %d pixels %ld byte/channel RLE row: %ld, channel: %ld\n", fWidth, fBytesPerChannel, y, z);
483
484			if (fBytesPerChannel == 1)
485				x = _WriteRLE8((uint8*)row, fWidth);
486			else
487				x = _WriteRLE16((uint16*)row, fWidth);
488
489			if (fCompression == SGI_COMP_ARLE) {
490				fARLEOffset = offset;
491				fARLELength = x;
492				memcpy(fARLERow, row, fWidth * fBytesPerChannel);
493			}
494
495			fNextRowOffset = fStream->Position();
496			fLengthTable[z][y] = x;
497
498			return x;
499		default:
500			break;
501	}
502
503	return ret;
504}
505
506// _ReadLong
507//
508// reads 4 bytes from the stream and
509// returns a 32-bit big-endian integer
510int32
511SGIImage::_ReadLong() const
512{
513	int32 n;
514	if (fStream->Read(&n, 4) == 4) {
515		return B_BENDIAN_TO_HOST_INT32(n);
516	} else
517		return 0;
518}
519
520// _ReadShort
521//
522// reads 2 bytes from the stream and
523// returns a 16-bit big-endian integer
524int16
525SGIImage::_ReadShort() const
526{
527	int16 n;
528	if (fStream->Read(&n, 2) == 2) {
529		return B_BENDIAN_TO_HOST_INT16(n);
530	} else
531		return 0;
532}
533
534// _ReadChar
535//
536// reads 1 byte from the stream and
537// returns it
538int8
539SGIImage::_ReadChar() const
540{
541	int8 b;
542	ssize_t read = fStream->Read(&b, 1);
543	if (read == 1)
544		return b;
545	else if (read < B_OK)
546		return (int8)read;
547	return (int8)B_ERROR;
548}
549
550// _WriteLong
551//
552// writes a 32-bit big-endian integer to the stream
553status_t
554SGIImage::_WriteLong(int32 n) const
555{
556	int32 bigN = B_HOST_TO_BENDIAN_INT32(n);
557	ssize_t written = fStream->Write(&bigN, sizeof(int32));
558	if (written == sizeof(int32))
559		return B_OK;
560	if (written < B_OK)
561		return written;
562	return B_ERROR;
563}
564
565// _WriteShort
566//
567// writes a 16-bit big-endian integer to the stream
568status_t
569SGIImage::_WriteShort(uint16 n) const
570{
571	uint16 bigN = B_HOST_TO_BENDIAN_INT16(n);
572	ssize_t written = fStream->Write(&bigN, sizeof(uint16));
573	if (written == sizeof(uint16))
574		return B_OK;
575	if (written < B_OK)
576		return written;
577	return B_ERROR;
578}
579
580// _WriteChar
581//
582// writes one byte to the stream
583status_t
584SGIImage::_WriteChar(int8 n) const
585{
586	ssize_t written = fStream->Write(&n, sizeof(int8));
587	if (written == sizeof(int8))
588		return B_OK;
589	if (written < B_OK)
590		return written;
591	return B_ERROR;
592}
593
594// _ReadRLE8
595//
596// reads 8-bit RLE data into provided buffer
597//
598// row			pointer to buffer for one row
599// numPixels	number of pixels that fit into row buffer
600ssize_t
601SGIImage::_ReadRLE8(uint8* row, int32 numPixels) const
602{
603	int32 ch;			// current charater
604	uint32 count;		// RLE count
605	uint32 length = 0;	// number of bytes read
606
607	uint32 bufferSize = 1024;
608	uint8* buffer = new uint8[bufferSize];
609	uint32 bufferPos = bufferSize;
610
611	status_t ret = B_OK;
612
613	while (numPixels > 0) {
614
615		// fetch another buffer if we need to
616		if (bufferPos >= bufferSize) {
617			ret = fStream->Read(buffer, bufferSize);
618			if (ret < B_OK)
619				break;
620			else
621				bufferPos = 0;
622		}
623
624		ch = buffer[bufferPos ++];
625		length ++;
626
627		count = ch & 127;
628		if (count == 0)
629			break;
630
631		if (ch & 128) {
632			for (uint32 i = 0; i < count; i++) {
633
634				// fetch another buffer if we need to
635				if (bufferPos >= bufferSize) {
636					ret = fStream->Read(buffer, bufferSize);
637					if (ret < B_OK) {
638						delete[] buffer;
639						return ret;
640					} else
641						bufferPos = 0;
642				}
643
644				*row = buffer[bufferPos ++];
645				row ++;
646				numPixels --;
647				length ++;
648			}
649		} else {
650
651			// fetch another buffer if we need to
652			if (bufferPos >= bufferSize) {
653				ret = fStream->Read(buffer, bufferSize);
654				if (ret < B_OK) {
655					delete[] buffer;
656					return ret;
657				} else
658					bufferPos = 0;
659			}
660
661			ch = buffer[bufferPos ++];
662			length ++;
663			for (uint32 i = 0; i < count; i++) {
664				*row = ch;
665				row ++;
666				numPixels --;
667			}
668		}
669	}
670	delete[] buffer;
671
672	return (numPixels > 0 ? ret : length);
673}
674
675// _ReadRLE8
676//
677// reads 8-bit RLE data into provided buffer
678//
679// row			pointer to buffer for one row
680// numPixels	number of pixels that fit into row buffer
681ssize_t
682SGIImage::_ReadRLE8(uint8* row, uint8* rleBuffer, int32 numPixels) const
683{
684	int32 ch;			// current charater
685	uint32 count;		// RLE count
686	uint32 length = 0;	// number of bytes read
687
688	if (numPixels <= 0)
689		return B_ERROR;
690
691	while (numPixels > 0) {
692
693		ch = *rleBuffer ++;
694		length ++;
695
696		count = ch & 127;
697		if (count == 0)
698			break;
699
700		if (ch & 128) {
701			for (uint32 i = 0; i < count; i++) {
702
703				*row = *rleBuffer ++;
704				row ++;
705				numPixels --;
706				length ++;
707			}
708		} else {
709
710			ch = *rleBuffer ++;
711			length ++;
712			for (uint32 i = 0; i < count; i++) {
713				*row = ch;
714				row ++;
715				numPixels --;
716			}
717		}
718	}
719
720	return length;
721}
722/*ssize_t
723SGIImage::_ReadRLE8(uint8* row, int32 numPixels) const
724{
725	int32 ch;			// current charater
726	uint32 count;		// RLE count
727	uint32 length = 0;	// number of bytes read
728
729	while (numPixels > 0) {
730		ch = _ReadChar();
731		length ++;
732
733		count = ch & 127;
734		if (count == 0)
735			break;
736
737		if (ch & 128) {
738			for (uint32 i = 0; i < count; i++) {
739				*row = _ReadChar();
740				row ++;
741				numPixels --;
742				length ++;
743			}
744		} else {
745			ch = _ReadChar();
746			length ++;
747			for (uint32 i = 0; i < count; i++) {
748				*row = ch;
749				row ++;
750				numPixels --;
751			}
752		}
753	}
754	return (numPixels > 0 ? B_ERROR : length);
755}*/
756
757// read_and_swap
758status_t
759read_and_swap(BPositionIO* stream, int16* buffer, uint32 size)
760{
761	status_t ret = stream->Read(buffer, size);
762	if (ret >= B_OK)
763		return swap_data(B_INT16_TYPE, buffer, ret, B_SWAP_BENDIAN_TO_HOST);
764	return ret;
765}
766
767// _ReadRLE16
768//
769// reads 16-bit RLE data into provided buffer
770//
771// row			pointer to buffer for one row
772// numPixels	number of pixels that fit into row buffer
773ssize_t
774SGIImage::_ReadRLE16(uint16* row, int32 numPixels) const
775{
776	int32 ch;			// current character
777	uint32 count;		// RLE count
778	uint32 length = 0;	// number of bytes read...
779
780	uint32 bufferSize = 1024;
781	int16* buffer = new int16[bufferSize];
782	uint32 bufferPos = bufferSize;
783	status_t ret = B_OK;
784
785	while (numPixels > 0) {
786
787		// fetch another buffer if we need to
788		if (bufferPos >= bufferSize) {
789			ret = read_and_swap(fStream, buffer, bufferSize * 2);
790			if (ret < B_OK)
791				break;
792			bufferPos = 0;
793		}
794
795		ch = buffer[bufferPos ++];
796		length ++;
797
798		count = ch & 127;
799		if (count == 0)
800			break;
801
802		if (ch & 128) {
803			for (uint32 i = 0; i < count; i++) {
804
805				// fetch another buffer if we need to
806				if (bufferPos >= bufferSize) {
807					ret = read_and_swap(fStream, buffer, bufferSize * 2);
808					if (ret < B_OK) {
809						delete[] buffer;
810						return ret;
811					} else
812						bufferPos = 0;
813				}
814
815				*row = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]);
816				row++;
817				numPixels--;
818				length++;
819			}
820		} else {
821
822			// fetch another buffer if we need to
823			if (bufferPos >= bufferSize) {
824				ret = read_and_swap(fStream, buffer, bufferSize * 2);
825				if (ret < B_OK) {
826					delete[] buffer;
827					return ret;
828				} else
829					bufferPos = 0;
830			}
831
832			ch = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]);
833			length ++;
834			for (uint32 i = 0; i < count; i++) {
835				*row = ch;
836				row++;
837				numPixels--;
838			}
839		}
840	}
841	delete[] buffer;
842	return (numPixels > 0 ? ret : length * 2);
843}
844
845// _ReadRLE16
846//
847// reads 16-bit RLE data into provided buffer
848//
849// row			pointer to buffer for one row
850// numPixels	number of pixels that fit into row buffer
851ssize_t
852SGIImage::_ReadRLE16(uint16* row, uint16* rleBuffer, int32 numPixels) const
853{
854	int32 ch;			// current character
855	uint32 count;		// RLE count
856	uint32 length = 0;	// number of bytes read...
857
858	if (numPixels <= 0)
859		return B_ERROR;
860
861	while (numPixels > 0) {
862
863		ch = *rleBuffer ++;
864		length ++;
865
866		count = ch & 127;
867		if (count == 0)
868			break;
869
870		if (ch & 128) {
871			for (uint32 i = 0; i < count; i++) {
872
873				*row = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++);
874				row++;
875				numPixels--;
876				length++;
877			}
878		} else {
879
880			ch = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++);
881			length ++;
882			for (uint32 i = 0; i < count; i++) {
883				*row = ch;
884				row++;
885				numPixels--;
886			}
887		}
888	}
889	return length * 2;
890}
891
892// _WriteRLE8
893//
894// writes 8-bit RLE data into the stream
895//
896// row			pointer to buffer for one row
897// numPixels	number of pixels that fit into row buffer
898ssize_t
899SGIImage::_WriteRLE8(uint8* row, int32 numPixels) const
900{
901	int32 length = 0;	// length of output line
902	int32 count;		// number of repeated/non-repeated pixels
903	int32 i;			// looping var
904	uint8* start;		// start of sequence
905	uint16 repeat;		// repeated pixel
906
907
908	for (int32 x = numPixels; x > 0;) {
909		start = row;
910		row   += 2;
911		x	 -= 2;
912
913		while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) {
914			row++;
915			x--;
916		}
917
918		row -= 2;
919		x   += 2;
920
921		count = row - start;
922		while (count > 0) {
923			i	 = count > 126 ? 126 : count;
924			count -= i;
925
926			if (_WriteChar(128 | i) == EOF)
927				return EOF;
928			length ++;
929
930			while (i > 0) {
931				if (_WriteChar(*start) == EOF)
932					return EOF;
933				start ++;
934				i --;
935				length ++;
936			}
937		}
938
939		if (x <= 0)
940			break;
941
942		start  = row;
943		repeat = row[0];
944
945		row ++;
946		x --;
947
948		while (x > 0 && *row == repeat) {
949			row ++;
950			x --;
951		}
952
953		count = row - start;
954		while (count > 0) {
955			i	 = count > 126 ? 126 : count;
956			count -= i;
957
958			if (_WriteChar(i) == EOF)
959				return EOF;
960			length ++;
961
962			if (_WriteChar(repeat) == EOF)
963				return (-1);
964			length ++;
965		}
966	}
967
968	length ++;
969
970	if (_WriteChar(0) == EOF)
971		return EOF;
972	else
973		return length;
974}
975
976
977// _WriteRLE16
978//
979// writes 16-bit RLE data into the stream
980//
981// row			pointer to buffer for one row
982// numPixels	number of pixels that fit into row buffer
983ssize_t
984SGIImage::_WriteRLE16(uint16* row, int32 numPixels) const
985{
986	int32 length = 0;	// length of output line
987	int32 count;		// number of repeated/non-repeated pixels
988	int32 i;			// looping var
989	int32 x;			// looping var
990	uint16* start;		// start of sequence
991	uint16 repeat;		// repeated pixel
992
993
994	for (x = numPixels; x > 0;) {
995		start = row;
996		row   += 2;
997		x	 -= 2;
998
999		while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) {
1000			row ++;
1001			x --;
1002		}
1003
1004		row -= 2;
1005		x   += 2;
1006
1007		count = row - start;
1008		while (count > 0) {
1009			i	 = count > 126 ? 126 : count;
1010			count -= i;
1011
1012			if (_WriteShort(128 | i) == EOF)
1013				return EOF;
1014			length ++;
1015
1016			while (i > 0) {
1017				if (_WriteShort(*start) == EOF)
1018					return EOF;
1019				start ++;
1020				i --;
1021				length ++;
1022			}
1023		}
1024
1025		if (x <= 0)
1026			break;
1027
1028		start  = row;
1029		repeat = row[0];
1030
1031		row ++;
1032		x --;
1033
1034		while (x > 0 && *row == repeat) {
1035			row ++;
1036			x --;
1037		}
1038
1039		count = row - start;
1040		while (count > 0) {
1041			i	 = count > 126 ? 126 : count;
1042			count -= i;
1043
1044			if (_WriteShort(i) == EOF)
1045				return EOF;
1046			length ++;
1047
1048			if (_WriteShort(repeat) == EOF)
1049				return EOF;
1050			length ++;
1051		}
1052	}
1053
1054	length ++;
1055
1056	if (_WriteShort(0) == EOF)
1057		return EOF;
1058	else
1059		return (2 * length);
1060}
1061
1062
1063