A run-length compression method used in MacPaint and TIFF image files. To decode a PackBits bitstream:
- Read a byte `runlen' from in.
- If runlen is in 0 to 127, copy runlen + 1 bytes verbatim from in to out.
- Else if runlen is in -127 to -1, read a byte runtext from in and write runtext to out runlen times.
- Otherwise, b is -128; this is considered a no-op.
- Rinse and repeat until the whole bitstream is decoded.
/* fpack() *****************************
* Write PackBits encoded data to a file.
* buf, fp: as fwrite()
* size: size of source (unpacked) buffer
* returns: number of packed bytes written
*/
size_t fpack(const unsigned char *buf, size_t size, FILE *fp)
{
char b[127];
unsigned int bdex = 0, i = 0, j = 0, t = 0;
do {
/* zero the line index */
i = 0;
/* check for a run of at least three bytes */
while((buf[t + i] == buf[t + i + 1]) &&
(buf[t + i] == buf[t + i + 2]) &&
(t + i + 3 < size) && (i < 126))
i++;
/* if there's a run... */
if((i > 0 && bdex > 0) || (bdex >= 127))
{
/* if there's a literal string... */
fputc(bdex - 1, fp);
j++;
/* write it to the file. */
j += fwrite(b, 1, bdex, fp);
bdex = 0;
}
if(i > 0)
{
/* and then write the run. */
i += 2;
fputc(257 - i, fp);
fputc(buf[t], fp);
t += i;
j += 2;
}
else
{
b[bdex++] = buf[t++];
}
} while(t < size);
if(bdex)
{
/* if there's a literal string... */
fputc(bdex - 1, fp);
j++;
/* write it to the file. */
j += fwrite(b, 1, bdex, fp);
bdex = 0;
}
return j;
}
/* funpack() ***************************
* Read PackBits() encoded data from a file.
* buf, fp: as fread()
* size: size of destination (unpacked) buffer
* returns: number of bytes unpacked
*/
int funpack(unsigned char *buffer, size_t size, FILE *file)
{
unsigned char mode;
size_t nread = 0;
int i;
while(nread < size)
{
mode = fgetc(file);
if(feof(file))
return nread;
if(mode > 128)
{
i = 257 - mode;
mode = fgetc(file);
if(feof(file))
return nread;
while(i--)
buffer[nread++] = mode;
}
else if(mode < 128)
nread += fread(buffer + nread, 1, mode + 1, file);
}
return nread;
}