xref: /haiku/src/add-ons/translators/sgi/SGIImage.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
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 	while (numPixels > 0) {
688 
689 		ch = *rleBuffer ++;
690 		length ++;
691 
692 		count = ch & 127;
693 		if (count == 0)
694 			break;
695 
696 		if (ch & 128) {
697 			for (uint32 i = 0; i < count; i++) {
698 
699 				*row = *rleBuffer ++;
700 				row ++;
701 				numPixels --;
702 				length ++;
703 			}
704 		} else {
705 
706 			ch = *rleBuffer ++;
707 			length ++;
708 			for (uint32 i = 0; i < count; i++) {
709 				*row = ch;
710 				row ++;
711 				numPixels --;
712 			}
713 		}
714 	}
715 
716 	return (numPixels > 0 ? B_ERROR : length);
717 }
718 /*ssize_t
719 SGIImage::_ReadRLE8(uint8* row, int32 numPixels) const
720 {
721 	int32 ch;			// current charater
722 	uint32 count;		// RLE count
723 	uint32 length = 0;	// number of bytes read
724 
725 	while (numPixels > 0) {
726 		ch = _ReadChar();
727 		length ++;
728 
729 		count = ch & 127;
730 		if (count == 0)
731 			break;
732 
733 		if (ch & 128) {
734 			for (uint32 i = 0; i < count; i++) {
735 				*row = _ReadChar();
736 				row ++;
737 				numPixels --;
738 				length ++;
739 			}
740 		} else {
741 			ch = _ReadChar();
742 			length ++;
743 			for (uint32 i = 0; i < count; i++) {
744 				*row = ch;
745 				row ++;
746 				numPixels --;
747 			}
748 		}
749 	}
750 	return (numPixels > 0 ? B_ERROR : length);
751 }*/
752 
753 // read_and_swap
754 status_t
755 read_and_swap(BPositionIO* stream, int16* buffer, uint32 size)
756 {
757 	status_t ret = stream->Read(buffer, size);
758 	if (ret >= B_OK)
759 		return swap_data(B_INT16_TYPE, buffer, ret, B_SWAP_BENDIAN_TO_HOST);
760 	return ret;
761 }
762 
763 // _ReadRLE16
764 //
765 // reads 16-bit RLE data into provided buffer
766 //
767 // row			pointer to buffer for one row
768 // numPixels	number of pixels that fit into row buffer
769 ssize_t
770 SGIImage::_ReadRLE16(uint16* row, int32 numPixels) const
771 {
772 	int32 ch;			// current character
773 	uint32 count;		// RLE count
774 	uint32 length = 0;	// number of bytes read...
775 
776 	uint32 bufferSize = 1024;
777 	int16* buffer = new int16[bufferSize];
778 	uint32 bufferPos = bufferSize;
779 	status_t ret = B_OK;
780 
781 	while (numPixels > 0) {
782 
783 		// fetch another buffer if we need to
784 		if (bufferPos >= bufferSize) {
785 			ret = read_and_swap(fStream, buffer, bufferSize * 2);
786 			if (ret < B_OK)
787 				break;
788 			bufferPos = 0;
789 		}
790 
791 		ch = buffer[bufferPos ++];
792 		length ++;
793 
794 		count = ch & 127;
795 		if (count == 0)
796 			break;
797 
798 		if (ch & 128) {
799 			for (uint32 i = 0; i < count; i++) {
800 
801 				// fetch another buffer if we need to
802 				if (bufferPos >= bufferSize) {
803 					ret = read_and_swap(fStream, buffer, bufferSize * 2);
804 					if (ret < B_OK) {
805 						delete[] buffer;
806 						return ret;
807 					} else
808 						bufferPos = 0;
809 				}
810 
811 				*row = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]);
812 				row++;
813 				numPixels--;
814 				length++;
815 			}
816 		} else {
817 
818 			// fetch another buffer if we need to
819 			if (bufferPos >= bufferSize) {
820 				ret = read_and_swap(fStream, buffer, bufferSize * 2);
821 				if (ret < B_OK) {
822 					delete[] buffer;
823 					return ret;
824 				} else
825 					bufferPos = 0;
826 			}
827 
828 			ch = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]);
829 			length ++;
830 			for (uint32 i = 0; i < count; i++) {
831 				*row = ch;
832 				row++;
833 				numPixels--;
834 			}
835 		}
836 	}
837 	delete[] buffer;
838 	return (numPixels > 0 ? ret : length * 2);
839 }
840 
841 // _ReadRLE16
842 //
843 // reads 16-bit RLE data into provided buffer
844 //
845 // row			pointer to buffer for one row
846 // numPixels	number of pixels that fit into row buffer
847 ssize_t
848 SGIImage::_ReadRLE16(uint16* row, uint16* rleBuffer, int32 numPixels) const
849 {
850 	int32 ch;			// current character
851 	uint32 count;		// RLE count
852 	uint32 length = 0;	// number of bytes read...
853 
854 	while (numPixels > 0) {
855 
856 		ch = *rleBuffer ++;
857 		length ++;
858 
859 		count = ch & 127;
860 		if (count == 0)
861 			break;
862 
863 		if (ch & 128) {
864 			for (uint32 i = 0; i < count; i++) {
865 
866 				*row = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++);
867 				row++;
868 				numPixels--;
869 				length++;
870 			}
871 		} else {
872 
873 			ch = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++);
874 			length ++;
875 			for (uint32 i = 0; i < count; i++) {
876 				*row = ch;
877 				row++;
878 				numPixels--;
879 			}
880 		}
881 	}
882 	return (numPixels > 0 ? B_ERROR : length * 2);
883 }
884 
885 // _WriteRLE8
886 //
887 // writes 8-bit RLE data into the stream
888 //
889 // row			pointer to buffer for one row
890 // numPixels	number of pixels that fit into row buffer
891 ssize_t
892 SGIImage::_WriteRLE8(uint8* row, int32 numPixels) const
893 {
894 	int32 length = 0;	// length of output line
895 	int32 count;		// number of repeated/non-repeated pixels
896 	int32 i;			// looping var
897 	uint8* start;		// start of sequence
898 	uint16 repeat;		// repeated pixel
899 
900 
901 	for (int32 x = numPixels; x > 0;) {
902 		start = row;
903 		row   += 2;
904 		x	 -= 2;
905 
906 		while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) {
907 			row++;
908 			x--;
909 		}
910 
911 		row -= 2;
912 		x   += 2;
913 
914 		count = row - start;
915 		while (count > 0) {
916 			i	 = count > 126 ? 126 : count;
917 			count -= i;
918 
919 			if (_WriteChar(128 | i) == EOF)
920 				return EOF;
921 			length ++;
922 
923 			while (i > 0) {
924 				if (_WriteChar(*start) == EOF)
925 					return EOF;
926 				start ++;
927 				i --;
928 				length ++;
929 			}
930 		}
931 
932 		if (x <= 0)
933 			break;
934 
935 		start  = row;
936 		repeat = row[0];
937 
938 		row ++;
939 		x --;
940 
941 		while (x > 0 && *row == repeat) {
942 			row ++;
943 			x --;
944 		}
945 
946 		count = row - start;
947 		while (count > 0) {
948 			i	 = count > 126 ? 126 : count;
949 			count -= i;
950 
951 			if (_WriteChar(i) == EOF)
952 				return EOF;
953 			length ++;
954 
955 			if (_WriteChar(repeat) == EOF)
956 				return (-1);
957 			length ++;
958 		}
959 	}
960 
961 	length ++;
962 
963 	if (_WriteChar(0) == EOF)
964 		return EOF;
965 	else
966 		return length;
967 }
968 
969 
970 // _WriteRLE16
971 //
972 // writes 16-bit RLE data into the stream
973 //
974 // row			pointer to buffer for one row
975 // numPixels	number of pixels that fit into row buffer
976 ssize_t
977 SGIImage::_WriteRLE16(uint16* row, int32 numPixels) const
978 {
979 	int32 length = 0;	// length of output line
980 	int32 count;		// number of repeated/non-repeated pixels
981 	int32 i;			// looping var
982 	int32 x;			// looping var
983 	uint16* start;		// start of sequence
984 	uint16 repeat;		// repeated pixel
985 
986 
987 	for (x = numPixels; x > 0;) {
988 		start = row;
989 		row   += 2;
990 		x	 -= 2;
991 
992 		while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) {
993 			row ++;
994 			x --;
995 		}
996 
997 		row -= 2;
998 		x   += 2;
999 
1000 		count = row - start;
1001 		while (count > 0) {
1002 			i	 = count > 126 ? 126 : count;
1003 			count -= i;
1004 
1005 			if (_WriteShort(128 | i) == EOF)
1006 				return EOF;
1007 			length ++;
1008 
1009 			while (i > 0) {
1010 				if (_WriteShort(*start) == EOF)
1011 					return EOF;
1012 				start ++;
1013 				i --;
1014 				length ++;
1015 			}
1016 		}
1017 
1018 		if (x <= 0)
1019 			break;
1020 
1021 		start  = row;
1022 		repeat = row[0];
1023 
1024 		row ++;
1025 		x --;
1026 
1027 		while (x > 0 && *row == repeat) {
1028 			row ++;
1029 			x --;
1030 		}
1031 
1032 		count = row - start;
1033 		while (count > 0) {
1034 			i	 = count > 126 ? 126 : count;
1035 			count -= i;
1036 
1037 			if (_WriteShort(i) == EOF)
1038 				return EOF;
1039 			length ++;
1040 
1041 			if (_WriteShort(repeat) == EOF)
1042 				return EOF;
1043 			length ++;
1044 		}
1045 	}
1046 
1047 	length ++;
1048 
1049 	if (_WriteShort(0) == EOF)
1050 		return EOF;
1051 	else
1052 		return (2 * length);
1053 }
1054 
1055 
1056