/*****************************************************************************/
// SGITranslator
// Written by Stephan Aßmus <stippi@yellowbites.com>
// derived from GIMP SGI plugin by Michael Sweet
//
// SGIImage.cpp
//
// SGI image file format library routines.
//
// Formed into a class SGIImage, adopted to Be API and modified to use
// BPositionIO, optimizations for buffered reading.
//
//
// Copyright (c) 2003 OpenBeOS Project
// Portions Copyright 1997-1998 Michael Sweet (mike@easysw.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <ByteOrder.h>
#include <DataIO.h>
#include <TranslationErrors.h>
#include "SGIImage.h"
const char kSGICopyright[] = "" B_UTF8_COPYRIGHT " 1997-1998 Michael Sweet "
"<mike@easysw.com>";
// constructor
SGIImage::SGIImage()
: fStream(NULL),
fMode(0),
fBytesPerChannel(0),
fCompression(0),
fWidth(0),
fHeight(0),
fChannelCount(0),
fFirstRowOffset(0),
fNextRowOffset(0),
fOffsetTable(NULL),
fLengthTable(NULL),
fARLERow(NULL),
fARLEOffset(0),
fARLELength(0)
{
}
// destructor
SGIImage::~SGIImage()
{
Unset();
}
// InitCheck
status_t
SGIImage::InitCheck() const
{
if (fStream)
return B_OK;
return B_NO_INIT;
}
// SetTo
// open an SGI image file for reading
//
// stream the input stream
status_t
SGIImage::SetTo(BPositionIO* stream)
{
if (!stream)
return B_BAD_VALUE;
fStream = stream;
stream->Seek(0, SEEK_SET);
int16 magic = _ReadShort();
if (magic != SGI_MAGIC) {
fStream = NULL;
return B_NO_TRANSLATOR;
}
fMode = SGI_READ;
fCompression = _ReadChar();
fBytesPerChannel = _ReadChar();
_ReadShort(); // Dimensions
fWidth = _ReadShort();
fHeight = _ReadShort();
fChannelCount = _ReadShort();
// _ReadLong(); // Minimum pixel
// _ReadLong(); // Maximum pixel
if (fCompression) {
// this stream is compressed; read the scanline tables...
fStream->Seek(512, SEEK_SET);
fOffsetTable = (int32**)calloc(fChannelCount, sizeof(int32*));
fOffsetTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
for (uint32 i = 1; i < fChannelCount; i++)
fOffsetTable[i] = fOffsetTable[0] + i * fHeight;
for (uint32 i = 0; i < fChannelCount; i++)
for (uint16 j = 0; j < fHeight; j++)
fOffsetTable[i][j] = _ReadLong();
fLengthTable = (int32**)calloc(fChannelCount, sizeof(int32*));
fLengthTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
for (int32 i = 1; i < fChannelCount; i ++)
fLengthTable[i] = fLengthTable[0] + i * fHeight;
for (uint32 i = 0; i < fChannelCount; i++)
for (uint16 j = 0; j < fHeight; j++)
fLengthTable[i][j] = _ReadLong();
}
return B_OK;
}
// SetTo
// open an SGI image file for writing
//
// stream the output stream
// width number of pixels in a row
// height number of rows
// channels number of channels per pixel
// bytesPerChannel number of bytes per channel
// compression compression mode
status_t
SGIImage::SetTo(BPositionIO* stream,
uint16 width, uint16 height,
uint16 channels, uint32 bytesPerChannel,
uint32 compression)
{
// sanity checks
if (!stream ||
width < 1 || height < 1 || channels < 1 ||
bytesPerChannel < 1 || bytesPerChannel > 2 ||
compression < SGI_COMP_NONE || compression > SGI_COMP_ARLE)
return B_BAD_VALUE;
fStream = stream;
fMode = SGI_WRITE;
_WriteShort(SGI_MAGIC);
_WriteChar((fCompression = compression) != 0);
_WriteChar(fBytesPerChannel = bytesPerChannel);
_WriteShort(3); // Dimensions
_WriteShort(fWidth = width);
_WriteShort(fHeight = height);
_WriteShort(fChannelCount = channels);
if (fBytesPerChannel == 1) {
_WriteLong(0); // Minimum pixel
_WriteLong(255); // Maximum pixel
} else {
_WriteLong(-32768); // Minimum pixel
_WriteLong(32767); // Maximum pixel
}
_WriteLong(0); // Reserved
char name[80]; // Name of file in image header
memset(name, 0, sizeof(name));
sprintf(name, "Haiku SGITranslator");
fStream->Write(name, sizeof(name));
// fill the rest of the image header with zeros
for (int32 i = 0; i < 102; i++)
_WriteLong(0);
switch (fCompression) {
case SGI_COMP_NONE : // No compression
// This file is uncompressed. To avoid problems with
// sparse files, we need to write blank pixels for the
// entire image...
/* if (fBytesPerChannel == 1) {
for (int32 i = fWidth * fHeight * fChannelCount; i > 0; i --)
_WriteChar(0);
} else {
for (int32 i = fWidth * fHeight * fChannelCount; i > 0; i --)
_WriteShort(0);
}*/
break;
case SGI_COMP_ARLE: // Aggressive RLE
fARLERow = (uint16*)calloc(fWidth, sizeof(uint16));
fARLEOffset = 0;
// FALL THROUGH
case SGI_COMP_RLE : // Run-Length Encoding
// This file is compressed; write the (blank) scanline tables...
// for (int32 i = 2 * fHeight * fChannelCount; i > 0; i--)
// _WriteLong(0);
fStream->Seek(2 * fHeight * fChannelCount * sizeof(int32), SEEK_CUR);
fFirstRowOffset = fStream->Position();
fNextRowOffset = fStream->Position();
// allocate and read offset table
fOffsetTable = (int32**)calloc(fChannelCount, sizeof(int32*));
fOffsetTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
for (int32 i = 1; i < fChannelCount; i ++)
fOffsetTable[i] = fOffsetTable[0] + i * fHeight;
// allocate and read length table
fLengthTable = (int32**)calloc(fChannelCount, sizeof(int32*));
fLengthTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32));
for (int32 i = 1; i < fChannelCount; i ++)
fLengthTable[i] = fLengthTable[0] + i * fHeight;
break;
}
return B_OK;
}
// Unset
//
// if in write mode, writes final information to the stream
status_t
SGIImage::Unset()
{
status_t ret = InitCheck(); // return status
if (ret >= B_OK) {
if (fMode == SGI_WRITE && fCompression != SGI_COMP_NONE) {
// write the scanline offset table to the file...
fStream->Seek(512, SEEK_SET);
/* off_t* offset = fOffsetTable[0];
for (int32 i = fHeight * fChannelCount; i > 0; i--) {
if ((ret = _WriteLong(offset[0])) < B_OK)
break;
offset++;
}*/
int32 size = fHeight * fChannelCount * sizeof(int32);
swap_data(B_INT32_TYPE, fOffsetTable[0], size, B_SWAP_HOST_TO_BENDIAN);
ret = fStream->Write(fOffsetTable[0], size);
if (ret >= B_OK) {
/* int32* length = fLengthTable[0];
for (int32 i = fHeight * fChannelCount; i > 0; i--) {
if ((ret = _WriteLong(length[0])) < B_OK)
break;
length++;
}*/
swap_data(B_INT32_TYPE, fLengthTable[0], size, B_SWAP_HOST_TO_BENDIAN);
ret = fStream->Write(fLengthTable[0], size);
}
}
if (fOffsetTable != NULL) {
free(fOffsetTable[0]);
free(fOffsetTable);
fOffsetTable = NULL;
}
if (fLengthTable != NULL) {
free(fLengthTable[0]);
free(fLengthTable);
fLengthTable = NULL;
}
if (fARLERow) {
free(fARLERow);
fARLERow = NULL;
}
fStream = NULL;
}
return ret;
}
// ReadRow
//
// reads a row of image data from the stream
//
// row pointer to buffer (row of pixels) to read
// y index (line number) of this row
// z which channel to read
status_t
SGIImage::ReadRow(void* row, int32 y, int32 z)
{
// sanitiy checks
if (row == NULL ||
y < 0 || y >= fHeight ||
z < 0 || z >= fChannelCount)
return B_BAD_VALUE;
status_t ret = B_ERROR;
switch (fCompression) {
case SGI_COMP_NONE: {
// seek to the image row
// optimize buffering by only seeking if necessary...
off_t offset = 512 + (y + z * fHeight) * fWidth * fBytesPerChannel;
fStream->Seek(offset, SEEK_SET);
uint32 bytes = fWidth * fBytesPerChannel;
//printf("reading %ld bytes 8 Bit uncompressed row: %ld, channel: %ld\n", bytes, y, z);
ret = fStream->Read(row, bytes);
break;
}
case SGI_COMP_RLE: {
int32 offset = fOffsetTable[z][y];
int32 rleLength = fLengthTable[z][y];
fStream->Seek(offset, SEEK_SET);
uint8* rleBuffer = new uint8[rleLength];
fStream->Read(rleBuffer, rleLength);
if (fBytesPerChannel == 1) {
//printf("reading 8 Bit RLE compressed row: %ld, channel: %ld\n", y, z);
// ret = _ReadRLE8((uint8*)row, fWidth);
ret = _ReadRLE8((uint8*)row, rleBuffer, fWidth);
} else {
//printf("reading 16 Bit RLE compressed row: %ld, channel: %ld\n", y, z);
// ret = _ReadRLE16((uint16*)row, fWidth);
if ((ret = swap_data(B_INT16_TYPE, rleBuffer, rleLength, B_SWAP_BENDIAN_TO_HOST)) >= B_OK)
ret = _ReadRLE16((uint16*)row, (uint16*)rleBuffer, fWidth);
}
delete[] rleBuffer;
break;
}
}
return ret;
}
// WriteRow
//
// writes a row of image data to the stream
//
// row pointer to buffer (row of pixels) to write
// y index (line number) of this row
// z which channel to write
status_t
SGIImage::WriteRow(void* row, int32 y, int32 z)
{
// sanitiy checks
if (row == NULL ||
y < 0 || y >= fHeight ||
z < 0 || z >= fChannelCount)
return B_BAD_VALUE;
int32 x; // x coordinate
int32 offset; // stream offset
status_t ret = B_ERROR;
switch (fCompression) {
case SGI_COMP_NONE: {
// Seek to the image row
offset = 512 + (y + z * fHeight) * fWidth * fBytesPerChannel;
fStream->Seek(offset, SEEK_SET);
uint32 bytes = fWidth * fBytesPerChannel;
//printf("writing %ld bytes %ld byte/channel uncompressed row: %ld, channel: %ld\n", bytes, fBytesPerChannel, y, z);
ret = fStream->Write(row, bytes);
/* if (fBytesPerChannel == 1) {
for (x = fWidth; x > 0; x--) {
_WriteChar(*row);
row++;
}
} else {
for (x = fWidth; x > 0; x--) {
_WriteShort(*row);
row++;
}
}*/
break;
}
case SGI_COMP_ARLE:
if (fOffsetTable[z][y] != 0)
return B_ERROR;
// First check the last row written...
if (fARLEOffset > 0) {
if (fBytesPerChannel == 1) {
uint8* arleRow = (uint8*)fARLERow;
uint8* src = (uint8*)row;
for (x = 0; x < fWidth; x++)
if (*src++ != *arleRow++)
break;
} else {
uint16* arleRow = (uint16*)fARLERow;
uint16* src = (uint16*)row;
for (x = 0; x < fWidth; x++)
if (*src++ != *arleRow++)
break;
}
if (x == fWidth) {
fOffsetTable[z][y] = fARLEOffset;
fLengthTable[z][y] = fARLELength;
return B_OK;
}
}
// If that didn't match, search all the previous rows...
fStream->Seek(fFirstRowOffset, SEEK_SET);
if (fBytesPerChannel == 1) {
do {
fARLEOffset = fStream->Position();
uint8* arleRow = (uint8*)fARLERow;
if ((fARLELength = _ReadRLE8(arleRow, fWidth)) < B_OK) {
x = 0;
break;
}
uint8* src = (uint8*)row;
for (x = 0; x < fWidth; x++)
if (*src++ != *arleRow++)
break;
} while (x < fWidth);
} else {
do {
fARLEOffset = fStream->Position();
uint16* arleRow = (uint16*)fARLERow;
if ((fARLELength = _ReadRLE16(arleRow, fWidth)) < B_OK) {
x = 0;
break;
}
uint16* src = (uint16*)row;
for (x = 0; x < fWidth; x++)
if (*src++ != *arleRow++)
break;
} while (x < fWidth);
}
if (x == fWidth) {
fOffsetTable[z][y] = fARLEOffset;
fLengthTable[z][y] = fARLELength;
return B_OK;
} else
fStream->Seek(0, SEEK_END); // seek to end of stream
// FALL THROUGH!
case SGI_COMP_RLE :
if (fOffsetTable[z][y] != 0)
return B_ERROR;
offset = fOffsetTable[z][y] = fNextRowOffset;
if (offset != fStream->Position())
fStream->Seek(offset, SEEK_SET);
//printf("writing %d pixels %ld byte/channel RLE row: %ld, channel: %ld\n", fWidth, fBytesPerChannel, y, z);
if (fBytesPerChannel == 1)
x = _WriteRLE8((uint8*)row, fWidth);
else
x = _WriteRLE16((uint16*)row, fWidth);
if (fCompression == SGI_COMP_ARLE) {
fARLEOffset = offset;
fARLELength = x;
memcpy(fARLERow, row, fWidth * fBytesPerChannel);
}
fNextRowOffset = fStream->Position();
fLengthTable[z][y] = x;
return x;
default:
break;
}
return ret;
}
// _ReadLong
//
// reads 4 bytes from the stream and
// returns a 32-bit big-endian integer
int32
SGIImage::_ReadLong() const
{
int32 n;
if (fStream->Read(&n, 4) == 4) {
return B_BENDIAN_TO_HOST_INT32(n);
} else
return 0;
}
// _ReadShort
//
// reads 2 bytes from the stream and
// returns a 16-bit big-endian integer
int16
SGIImage::_ReadShort() const
{
int16 n;
if (fStream->Read(&n, 2) == 2) {
return B_BENDIAN_TO_HOST_INT16(n);
} else
return 0;
}
// _ReadChar
//
// reads 1 byte from the stream and
// returns it
int8
SGIImage::_ReadChar() const
{
int8 b;
ssize_t read = fStream->Read(&b, 1);
if (read == 1)
return b;
else if (read < B_OK)
return (int8)read;
return (int8)B_ERROR;
}
// _WriteLong
//
// writes a 32-bit big-endian integer to the stream
status_t
SGIImage::_WriteLong(int32 n) const
{
int32 bigN = B_HOST_TO_BENDIAN_INT32(n);
ssize_t written = fStream->Write(&bigN, sizeof(int32));
if (written == sizeof(int32))
return B_OK;
if (written < B_OK)
return written;
return B_ERROR;
}
// _WriteShort
//
// writes a 16-bit big-endian integer to the stream
status_t
SGIImage::_WriteShort(uint16 n) const
{
uint16 bigN = B_HOST_TO_BENDIAN_INT16(n);
ssize_t written = fStream->Write(&bigN, sizeof(uint16));
if (written == sizeof(uint16))
return B_OK;
if (written < B_OK)
return written;
return B_ERROR;
}
// _WriteChar
//
// writes one byte to the stream
status_t
SGIImage::_WriteChar(int8 n) const
{
ssize_t written = fStream->Write(&n, sizeof(int8));
if (written == sizeof(int8))
return B_OK;
if (written < B_OK)
return written;
return B_ERROR;
}
// _ReadRLE8
//
// reads 8-bit RLE data into provided buffer
//
// row pointer to buffer for one row
// numPixels number of pixels that fit into row buffer
ssize_t
SGIImage::_ReadRLE8(uint8* row, int32 numPixels) const
{
int32 ch; // current charater
uint32 count; // RLE count
uint32 length = 0; // number of bytes read
uint32 bufferSize = 1024;
uint8* buffer = new uint8[bufferSize];
uint32 bufferPos = bufferSize;
status_t ret = B_OK;
while (numPixels > 0) {
// fetch another buffer if we need to
if (bufferPos >= bufferSize) {
ret = fStream->Read(buffer, bufferSize);
if (ret < B_OK)
break;
else
bufferPos = 0;
}
ch = buffer[bufferPos ++];
length ++;
count = ch & 127;
if (count == 0)
break;
if (ch & 128) {
for (uint32 i = 0; i < count; i++) {
// fetch another buffer if we need to
if (bufferPos >= bufferSize) {
ret = fStream->Read(buffer, bufferSize);
if (ret < B_OK) {
delete[] buffer;
return ret;
} else
bufferPos = 0;
}
*row = buffer[bufferPos ++];
row ++;
numPixels --;
length ++;
}
} else {
// fetch another buffer if we need to
if (bufferPos >= bufferSize) {
ret = fStream->Read(buffer, bufferSize);
if (ret < B_OK) {
delete[] buffer;
return ret;
} else
bufferPos = 0;
}
ch = buffer[bufferPos ++];
length ++;
for (uint32 i = 0; i < count; i++) {
*row = ch;
row ++;
numPixels --;
}
}
}
delete[] buffer;
return (numPixels > 0 ? ret : length);
}
// _ReadRLE8
//
// reads 8-bit RLE data into provided buffer
//
// row pointer to buffer for one row
// numPixels number of pixels that fit into row buffer
ssize_t
SGIImage::_ReadRLE8(uint8* row, uint8* rleBuffer, int32 numPixels) const
{
int32 ch; // current charater
uint32 count; // RLE count
uint32 length = 0; // number of bytes read
if (numPixels <= 0)
return B_ERROR;
while (numPixels > 0) {
ch = *rleBuffer ++;
length ++;
count = ch & 127;
if (count == 0)
break;
if (ch & 128) {
for (uint32 i = 0; i < count; i++) {
*row = *rleBuffer ++;
row ++;
numPixels --;
length ++;
}
} else {
ch = *rleBuffer ++;
length ++;
for (uint32 i = 0; i < count; i++) {
*row = ch;
row ++;
numPixels --;
}
}
}
return length;
}
/*ssize_t
SGIImage::_ReadRLE8(uint8* row, int32 numPixels) const
{
int32 ch; // current charater
uint32 count; // RLE count
uint32 length = 0; // number of bytes read
while (numPixels > 0) {
ch = _ReadChar();
length ++;
count = ch & 127;
if (count == 0)
break;
if (ch & 128) {
for (uint32 i = 0; i < count; i++) {
*row = _ReadChar();
row ++;
numPixels --;
length ++;
}
} else {
ch = _ReadChar();
length ++;
for (uint32 i = 0; i < count; i++) {
*row = ch;
row ++;
numPixels --;
}
}
}
return (numPixels > 0 ? B_ERROR : length);
}*/
// read_and_swap
status_t
read_and_swap(BPositionIO* stream, int16* buffer, uint32 size)
{
status_t ret = stream->Read(buffer, size);
if (ret >= B_OK)
return swap_data(B_INT16_TYPE, buffer, ret, B_SWAP_BENDIAN_TO_HOST);
return ret;
}
// _ReadRLE16
//
// reads 16-bit RLE data into provided buffer
//
// row pointer to buffer for one row
// numPixels number of pixels that fit into row buffer
ssize_t
SGIImage::_ReadRLE16(uint16* row, int32 numPixels) const
{
int32 ch; // current character
uint32 count; // RLE count
uint32 length = 0; // number of bytes read...
uint32 bufferSize = 1024;
int16* buffer = new int16[bufferSize];
uint32 bufferPos = bufferSize;
status_t ret = B_OK;
while (numPixels > 0) {
// fetch another buffer if we need to
if (bufferPos >= bufferSize) {
ret = read_and_swap(fStream, buffer, bufferSize * 2);
if (ret < B_OK)
break;
bufferPos = 0;
}
ch = buffer[bufferPos ++];
length ++;
count = ch & 127;
if (count == 0)
break;
if (ch & 128) {
for (uint32 i = 0; i < count; i++) {
// fetch another buffer if we need to
if (bufferPos >= bufferSize) {
ret = read_and_swap(fStream, buffer, bufferSize * 2);
if (ret < B_OK) {
delete[] buffer;
return ret;
} else
bufferPos = 0;
}
*row = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]);
row++;
numPixels--;
length++;
}
} else {
// fetch another buffer if we need to
if (bufferPos >= bufferSize) {
ret = read_and_swap(fStream, buffer, bufferSize * 2);
if (ret < B_OK) {
delete[] buffer;
return ret;
} else
bufferPos = 0;
}
ch = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]);
length ++;
for (uint32 i = 0; i < count; i++) {
*row = ch;
row++;
numPixels--;
}
}
}
delete[] buffer;
return (numPixels > 0 ? ret : length * 2);
}
// _ReadRLE16
//
// reads 16-bit RLE data into provided buffer
//
// row pointer to buffer for one row
// numPixels number of pixels that fit into row buffer
ssize_t
SGIImage::_ReadRLE16(uint16* row, uint16* rleBuffer, int32 numPixels) const
{
int32 ch; // current character
uint32 count; // RLE count
uint32 length = 0; // number of bytes read...
if (numPixels <= 0)
return B_ERROR;
while (numPixels > 0) {
ch = *rleBuffer ++;
length ++;
count = ch & 127;
if (count == 0)
break;
if (ch & 128) {
for (uint32 i = 0; i < count; i++) {
*row = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++);
row++;
numPixels--;
length++;
}
} else {
ch = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++);
length ++;
for (uint32 i = 0; i < count; i++) {
*row = ch;
row++;
numPixels--;
}
}
}
return length * 2;
}
// _WriteRLE8
//
// writes 8-bit RLE data into the stream
//
// row pointer to buffer for one row
// numPixels number of pixels that fit into row buffer
ssize_t
SGIImage::_WriteRLE8(uint8* row, int32 numPixels) const
{
int32 length = 0; // length of output line
int32 count; // number of repeated/non-repeated pixels
int32 i; // looping var
uint8* start; // start of sequence
uint16 repeat; // repeated pixel
for (int32 x = numPixels; x > 0;) {
start = row;
row += 2;
x -= 2;
while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) {
row++;
x--;
}
row -= 2;
x += 2;
count = row - start;
while (count > 0) {
i = count > 126 ? 126 : count;
count -= i;
if (_WriteChar(128 | i) == EOF)
return EOF;
length ++;
while (i > 0) {
if (_WriteChar(*start) == EOF)
return EOF;
start ++;
i --;
length ++;
}
}
if (x <= 0)
break;
start = row;
repeat = row[0];
row ++;
x --;
while (x > 0 && *row == repeat) {
row ++;
x --;
}
count = row - start;
while (count > 0) {
i = count > 126 ? 126 : count;
count -= i;
if (_WriteChar(i) == EOF)
return EOF;
length ++;
if (_WriteChar(repeat) == EOF)
return (-1);
length ++;
}
}
length ++;
if (_WriteChar(0) == EOF)
return EOF;
else
return length;
}
// _WriteRLE16
//
// writes 16-bit RLE data into the stream
//
// row pointer to buffer for one row
// numPixels number of pixels that fit into row buffer
ssize_t
SGIImage::_WriteRLE16(uint16* row, int32 numPixels) const
{
int32 length = 0; // length of output line
int32 count; // number of repeated/non-repeated pixels
int32 i; // looping var
int32 x; // looping var
uint16* start; // start of sequence
uint16 repeat; // repeated pixel
for (x = numPixels; x > 0;) {
start = row;
row += 2;
x -= 2;
while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) {
row ++;
x --;
}
row -= 2;
x += 2;
count = row - start;
while (count > 0) {
i = count > 126 ? 126 : count;
count -= i;
if (_WriteShort(128 | i) == EOF)
return EOF;
length ++;
while (i > 0) {
if (_WriteShort(*start) == EOF)
return EOF;
start ++;
i --;
length ++;
}
}
if (x <= 0)
break;
start = row;
repeat = row[0];
row ++;
x --;
while (x > 0 && *row == repeat) {
row ++;
x --;
}
count = row - start;
while (count > 0) {
i = count > 126 ? 126 : count;
count -= i;
if (_WriteShort(i) == EOF)
return EOF;
length ++;
if (_WriteShort(repeat) == EOF)
return EOF;
length ++;
}
}
length ++;
if (_WriteShort(0) == EOF)
return EOF;
else
return (2 * length);
}
↑ V595 The 'fOffsetTable' pointer was utilized before it was verified against nullptr. Check lines: 262, 279.
↑ V595 The 'fLengthTable' pointer was utilized before it was verified against nullptr. Check lines: 274, 285.