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