|
Campbell Barton |
d869b5 |
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
|
Toshihiro Shimizu |
890ddd |
#define _CRT_SECURE_NO_DEPRECATE 1
|
|
Toshihiro Shimizu |
890ddd |
#endif
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "zlib.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
#include "psdutils.h"
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void readrow(FILE *psd, TPSDChannelInfo *chan,
|
|
Shinya Kitaoka |
120a6e |
psdPixel row, // row index
|
|
Shinya Kitaoka |
120a6e |
unsigned char *inbuffer, // dest buffer for the uncompressed row
|
|
Shinya Kitaoka |
120a6e |
unsigned char *
|
|
Shinya Kitaoka |
120a6e |
tmpbuffer) // temp rlebuffer for compressed data, 2xrb in size
|
|
Toshihiro Shimizu |
890ddd |
{
|
|
Shinya Kitaoka |
120a6e |
psdPixel n = 0, rlebytes;
|
|
Shinya Kitaoka |
120a6e |
psdByte pos;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
int seekres = 0;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
switch (chan->comptype) {
|
|
Shinya Kitaoka |
120a6e |
case RAWDATA: /* uncompressed */
|
|
Shinya Kitaoka |
120a6e |
pos = chan->filepos + chan->rowbytes * row;
|
|
Shinya Kitaoka |
120a6e |
seekres = fseek(psd, pos, SEEK_SET);
|
|
Shinya Kitaoka |
120a6e |
if (seekres != -1) n = fread(inbuffer, 1, chan->rowbytes, psd);
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
case RLECOMP:
|
|
Shinya Kitaoka |
120a6e |
pos = chan->rowpos[row];
|
|
Shinya Kitaoka |
120a6e |
seekres = fseek(psd, pos, SEEK_SET);
|
|
Shinya Kitaoka |
120a6e |
if (seekres != -1) {
|
|
Shinya Kitaoka |
120a6e |
rlebytes = fread(tmpbuffer, 1, chan->rowpos[row + 1] - pos, psd);
|
|
Shinya Kitaoka |
120a6e |
n = unpackrow(inbuffer, tmpbuffer, chan->rowbytes, rlebytes);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
break;
|
|
Shinya Kitaoka |
120a6e |
case ZIPWITHPREDICTION:
|
|
Shinya Kitaoka |
120a6e |
case ZIPWITHOUTPREDICTION:
|
|
Shinya Kitaoka |
120a6e |
memcpy(inbuffer, chan->unzipdata + chan->rowbytes * row, chan->rowbytes);
|
|
Shinya Kitaoka |
120a6e |
return;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
// if we don't recognise the compression type, skip the row
|
|
Shinya Kitaoka |
120a6e |
// FIXME: or would it be better to use the last valid type seen?
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
// if(seekres == -1)
|
|
Shinya Kitaoka |
120a6e |
// alwayswarn("# can't seek to " LL_L("%lld\n","%ld\n"), pos);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (n < chan->rowbytes) {
|
|
Shinya Kitaoka |
120a6e |
// warn("row data short (wanted %d, got %d bytes)", chan->rowbytes, n);
|
|
Shinya Kitaoka |
120a6e |
// zero out unwritten part of row
|
|
Shinya Kitaoka |
120a6e |
memset(inbuffer + n, 0, chan->rowbytes - n);
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
int unpackrow(unsigned char *out, unsigned char *in, psdPixel outlen,
|
|
Shinya Kitaoka |
120a6e |
psdPixel inlen) {
|
|
Shinya Kitaoka |
120a6e |
psdPixel i, len;
|
|
Shinya Kitaoka |
120a6e |
int val;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
for (i = 0; inlen > 1 && i < outlen;) {
|
|
Shinya Kitaoka |
120a6e |
len = *in++;
|
|
Shinya Kitaoka |
120a6e |
--inlen;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if (len == 128) /* ignore RLE flag value */
|
|
Shinya Kitaoka |
120a6e |
;
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
if (len > 128) {
|
|
Shinya Kitaoka |
120a6e |
len = 1 + 256 - len;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
val = *in++;
|
|
Shinya Kitaoka |
120a6e |
--inlen;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
if ((i + len) <= outlen)
|
|
Shinya Kitaoka |
120a6e |
memset(out, val, len);
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
memset(out, val, outlen - i); // fill to complete row
|
|
Shinya Kitaoka |
120a6e |
len = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
++len;
|
|
Shinya Kitaoka |
120a6e |
if ((i + len) <= outlen) {
|
|
Shinya Kitaoka |
120a6e |
if (len > inlen) break;
|
|
Shinya Kitaoka |
120a6e |
memcpy(out, in, len);
|
|
Shinya Kitaoka |
120a6e |
in += len;
|
|
Shinya Kitaoka |
120a6e |
inlen -= len;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
memcpy(out, in, outlen - i); // copy to complete row
|
|
Shinya Kitaoka |
120a6e |
len = 0;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
out += len;
|
|
Shinya Kitaoka |
120a6e |
i += len;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
if (i < outlen) {
|
|
Shinya Kitaoka |
120a6e |
// WARNING: not enough RLE data for row;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return i;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void skipBlock(FILE *f) {
|
|
Shinya Kitaoka |
120a6e |
psdByte n = read4Bytes(f);
|
|
Shinya Kitaoka |
120a6e |
if (n) {
|
|
Shinya Kitaoka |
120a6e |
fseek(f, n, SEEK_CUR);
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Read 2byte unsigned binary value.
|
|
Toshihiro Shimizu |
890ddd |
// BigEndian.
|
|
Shinya Kitaoka |
120a6e |
unsigned read2UBytes(FILE *f) {
|
|
Shinya Kitaoka |
120a6e |
unsigned n = fgetc(f) << 8;
|
|
Shinya Kitaoka |
120a6e |
return n |= fgetc(f);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
// Read 2byte binary value
|
|
Toshihiro Shimizu |
890ddd |
// BigEndian.
|
|
Shinya Kitaoka |
120a6e |
int read2Bytes(FILE *f) {
|
|
Shinya Kitaoka |
120a6e |
unsigned n = fgetc(f) << 8;
|
|
Shinya Kitaoka |
120a6e |
n |= fgetc(f);
|
|
Shinya Kitaoka |
120a6e |
return n < 0x8000 ? n : n - 0x10000;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// Read 4byte signed binary value.
|
|
Toshihiro Shimizu |
890ddd |
// BigEndian.
|
|
Shinya Kitaoka |
120a6e |
long read4Bytes(FILE *f) {
|
|
Shinya Kitaoka |
120a6e |
long n = fgetc(f) << 24;
|
|
Shinya Kitaoka |
120a6e |
n |= fgetc(f) << 16;
|
|
Shinya Kitaoka |
120a6e |
n |= fgetc(f) << 8;
|
|
Shinya Kitaoka |
120a6e |
return n | fgetc(f);
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
void *mymalloc(long n) {
|
|
Shinya Kitaoka |
120a6e |
void *p = malloc(n);
|
|
Shinya Kitaoka |
120a6e |
if (p)
|
|
Shinya Kitaoka |
120a6e |
return p;
|
|
Shinya Kitaoka |
120a6e |
else {
|
|
Shinya Kitaoka |
120a6e |
// ALLOCATION ERROR
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
return NULL;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// ZIP COMPRESSION
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// ZIP WITHOUT PREDICTION
|
|
Toshihiro Shimizu |
890ddd |
// If no error returns 1 else returns 0
|
|
Toshihiro Shimizu |
890ddd |
int psdUnzipWithoutPrediction(unsigned char *src_buf, int src_len,
|
|
Shinya Kitaoka |
120a6e |
unsigned char *dst_buf, int dst_len) {
|
|
Shinya Kitaoka |
120a6e |
z_stream stream;
|
|
Shinya Kitaoka |
120a6e |
int state;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
memset(&stream, 0, sizeof(z_stream));
|
|
Shinya Kitaoka |
120a6e |
stream.data_type = Z_BINARY;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
stream.next_in = (Bytef *)src_buf;
|
|
Shinya Kitaoka |
120a6e |
stream.avail_in = src_len;
|
|
Shinya Kitaoka |
120a6e |
stream.next_out = (Bytef *)dst_buf;
|
|
Shinya Kitaoka |
120a6e |
stream.avail_out = dst_len;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (inflateInit(&stream) != Z_OK) return 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
do {
|
|
Shinya Kitaoka |
120a6e |
state = inflate(&stream, Z_PARTIAL_FLUSH);
|
|
Shinya Kitaoka |
120a6e |
if (state == Z_STREAM_END) break;
|
|
Shinya Kitaoka |
120a6e |
if (state == Z_DATA_ERROR || state != Z_OK) break;
|
|
Shinya Kitaoka |
120a6e |
} while (stream.avail_out > 0);
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
if (state != Z_STREAM_END && state != Z_OK) return 0;
|
|
Toshihiro Shimizu |
890ddd |
|
|
Shinya Kitaoka |
120a6e |
return 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
// ZIP WITH PREDICTION
|
|
Toshihiro Shimizu |
890ddd |
|
|
Toshihiro Shimizu |
890ddd |
int psdUnzipWithPrediction(unsigned char *src_buf, int src_len,
|
|
Shinya Kitaoka |
120a6e |
unsigned char *dst_buf, int dst_len, int row_size,
|
|
Shinya Kitaoka |
120a6e |
int color_depth) {
|
|
Shinya Kitaoka |
120a6e |
int status;
|
|
Shinya Kitaoka |
120a6e |
int len;
|
|
Shinya Kitaoka |
120a6e |
unsigned char *buf;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
status = psdUnzipWithoutPrediction(src_buf, src_len, dst_buf, dst_len);
|
|
Shinya Kitaoka |
120a6e |
if (!status) return status;
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
buf = dst_buf;
|
|
Shinya Kitaoka |
120a6e |
do {
|
|
Shinya Kitaoka |
120a6e |
len = row_size;
|
|
Shinya Kitaoka |
120a6e |
if (color_depth == 16) {
|
|
Shinya Kitaoka |
120a6e |
while (--len) {
|
|
Shinya Kitaoka |
120a6e |
buf[2] += buf[0] + ((buf[1] + buf[3]) >> 8);
|
|
Shinya Kitaoka |
120a6e |
buf[3] += buf[1];
|
|
Shinya Kitaoka |
120a6e |
buf += 2;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
buf += 2;
|
|
Shinya Kitaoka |
120a6e |
dst_len -= row_size * 2;
|
|
Shinya Kitaoka |
120a6e |
} else {
|
|
Shinya Kitaoka |
120a6e |
while (--len) {
|
|
Shinya Kitaoka |
120a6e |
*(buf + 1) += *buf;
|
|
Shinya Kitaoka |
120a6e |
buf++;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
buf++;
|
|
Shinya Kitaoka |
120a6e |
dst_len -= row_size;
|
|
Shinya Kitaoka |
120a6e |
}
|
|
Shinya Kitaoka |
120a6e |
} while (dst_len > 0);
|
|
Shinya Kitaoka |
120a6e |
|
|
Shinya Kitaoka |
120a6e |
return 1;
|
|
Toshihiro Shimizu |
890ddd |
}
|