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