xref: /haiku/src/add-ons/translators/sgi/SGIImage.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 
46 const char kSGICopyright[] = "" B_UTF8_COPYRIGHT " 1997-1998 Michael Sweet "
47 	"<mike@easysw.com>";
48 
49 // constructor
50 SGIImage::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
69 SGIImage::~SGIImage()
70 {
71 	Unset();
72 }
73 
74 // InitCheck
75 status_t
76 SGIImage::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
87 status_t
88 SGIImage::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
150 status_t
151 SGIImage::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);
216 fStream->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
242 status_t
243 SGIImage::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 
260 int32 size = fHeight * fChannelCount * sizeof(int32);
261 swap_data(B_INT32_TYPE, fOffsetTable[0], size, B_SWAP_HOST_TO_BENDIAN);
262 ret = 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 
273 swap_data(B_INT32_TYPE, fLengthTable[0], size, B_SWAP_HOST_TO_BENDIAN);
274 ret = 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
308 status_t
309 SGIImage::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
365 status_t
366 SGIImage::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
510 int32
511 SGIImage::_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
524 int16
525 SGIImage::_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
538 int8
539 SGIImage::_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
553 status_t
554 SGIImage::_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
568 status_t
569 SGIImage::_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
583 status_t
584 SGIImage::_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
600 ssize_t
601 SGIImage::_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
681 ssize_t
682 SGIImage::_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
723 SGIImage::_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
758 status_t
759 read_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
773 ssize_t
774 SGIImage::_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
851 ssize_t
852 SGIImage::_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
898 ssize_t
899 SGIImage::_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
983 ssize_t
984 SGIImage::_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