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
SGIImage()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
~SGIImage()69 SGIImage::~SGIImage()
70 {
71 Unset();
72 }
73
74 // InitCheck
75 status_t
InitCheck() const76 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
SetTo(BPositionIO * stream)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
SetTo(BPositionIO * stream,uint16 width,uint16 height,uint16 channels,uint32 bytesPerChannel,uint32 compression)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
Unset()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
ReadRow(void * row,int32 y,int32 z)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
WriteRow(void * row,int32 y,int32 z)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
_ReadLong() const511 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
_ReadShort() const525 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
_ReadChar() const539 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
_WriteLong(int32 n) const554 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
_WriteShort(uint16 n) const569 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
_WriteChar(int8 n) const584 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
_ReadRLE8(uint8 * row,int32 numPixels) const601 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
_ReadRLE8(uint8 * row,uint8 * rleBuffer,int32 numPixels) const682 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
read_and_swap(BPositionIO * stream,int16 * buffer,uint32 size)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
_ReadRLE16(uint16 * row,int32 numPixels) const774 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
_ReadRLE16(uint16 * row,uint16 * rleBuffer,int32 numPixels) const852 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
_WriteRLE8(uint8 * row,int32 numPixels) const899 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
_WriteRLE16(uint16 * row,int32 numPixels) const984 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