diff options
Diffstat (limited to 'saga/animation.cpp')
| -rw-r--r-- | saga/animation.cpp | 162 | 
1 files changed, 96 insertions, 66 deletions
| diff --git a/saga/animation.cpp b/saga/animation.cpp index 7768ad2294..b92d81f296 100644 --- a/saga/animation.cpp +++ b/saga/animation.cpp @@ -31,6 +31,7 @@  #include "saga/render.h"  #include "saga/animation.h" +#include "saga/stream.h"  namespace Saga { @@ -105,7 +106,7 @@ int Anim::load(const byte *anim_resdata, size_t anim_resdata_len, uint16 *anim_i  			getFrameOffset(anim_resdata, anim_resdata_len, i + 1, &new_anim->frame_offsets[i]);  		}  	} else { -		new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN; +		new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN; // ? len - may vary  		new_anim->cur_frame_len = anim_resdata_len - SAGA_FRAME_HEADER_LEN;  		getNumFrames(anim_resdata, anim_resdata_len, &new_anim->n_frames);  	} @@ -372,12 +373,13 @@ int Anim::getNumFrames(const byte *anim_resource, size_t anim_resource_len, uint  	if (!_initialized) {  		return FAILURE;  	} +	 -	MemoryReadStream readS(anim_resource, anim_resource_len); +	MemoryReadStreamEndian readS(anim_resource, anim_resource_len, IS_BIG_ENDIAN); -	ah.magic = readS.readUint16LE(); -	ah.screen_w = readS.readUint16LE(); -	ah.screen_h = readS.readUint16LE(); +	ah.magic = readS.readUint16LE(); // cause ALWAYS LE +	ah.screen_w = readS.readUint16(); +	ah.screen_h = readS.readUint16();  	ah.unknown06 = readS.readByte();  	ah.unknown07 = readS.readByte(); @@ -394,7 +396,7 @@ int Anim::getNumFrames(const byte *anim_resource, size_t anim_resource_len, uint  			}  			magic = *(anim_resource + offset); -			if (magic == SAGA_FRAME_HEADER_MAGIC) { +			if (magic == SAGA_FRAME_START) {  				*n_frames = x;  				return SUCCESS;  			} @@ -435,11 +437,11 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_  		return FAILURE;  	} -	MemoryReadStream headerReadS(resdata, resdata_len); +	MemoryReadStreamEndian headerReadS(resdata, resdata_len, IS_BIG_ENDIAN);  	// Read animation header  	ah.magic = headerReadS.readUint16LE(); -	ah.screen_w = headerReadS.readUint16LE(); -	ah.screen_h = headerReadS.readUint16LE(); +	ah.screen_w = headerReadS.readUint16(); +	ah.screen_h = headerReadS.readUint16();  	ah.unknown06 = headerReadS.readByte();  	ah.unknown07 = headerReadS.readByte();  	ah.nframes = headerReadS.readByte(); @@ -456,22 +458,21 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_  		return FAILURE;  	} -	// Read frame header  	MemoryReadStream readS(resdata + frame_offset, resdata_len - frame_offset);  	// Check for frame magic byte  	magic = readS.readByte(); -	if (magic != SAGA_FRAME_HEADER_MAGIC) { +	if (magic != SAGA_FRAME_START) {  		warning("ITE_DecodeFrame: Invalid frame offset");  		return FAILURE;  	} -	// For some strange reason, the animation header is in little  -	// endian format, but the actual RLE encoded frame data,  -	// including the frame header, is in big endian format.  	fh.x_start = readS.readUint16BE(); -	fh.y_start = readS.readByte(); +	if (IS_MAC_VERSION) +		fh.y_start = readS.readUint16BE(); +	else +		fh.y_start = readS.readByte();  	readS.readByte();		/* Skip pad byte */  	fh.x_pos = readS.readUint16BE();  	fh.y_pos = readS.readUint16BE(); @@ -481,14 +482,25 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_  	x_start = fh.x_start;  	y_start = fh.y_start; +#if 1 +#define VALIDATE_WRITE_POINTER \ +	if ((write_p < buf) || (write_p >= (buf + screen_w * screen_h))) { \ +		warning("VALIDATE_WRITE_POINTER: write_p=%x buf=%x", write_p, buf); \ +		return FAILURE; \ +	} +#else +#define VALIDATE_WRITE_POINTER  +#endif +  	// Setup write pointer to the draw origin  	write_p = (buf + (y_start * screen_w) + x_start); +	VALIDATE_WRITE_POINTER;  	// Begin RLE decompression to output buffer  	do {  		mark_byte = readS.readByte();  		switch (mark_byte) { -		case 0x10: // Long Unencoded Run +		case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // Long Unencoded Run  			runcount = readS.readSint16BE();  			for (i = 0; i < runcount; i++) {  				data_byte = readS.readByte(); @@ -496,30 +508,39 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_  					*write_p = data_byte;  				}  				write_p++; +				VALIDATE_WRITE_POINTER;  			}  			continue;  			break; -		case 0x20: // Long encoded run +		case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long encoded run  			runcount = readS.readSint16BE();  			data_byte = readS.readByte();  			for (i = 0; i < runcount; i++) {  				*write_p++ = data_byte; +				VALIDATE_WRITE_POINTER;  			}  			continue;  			break; -		case 0x2F: // End of row +		case SAGA_FRAME_ROW_END: // End of row  			x_vector = readS.readSint16BE(); -			new_row = readS.readByte(); +			 +			if (IS_MAC_VERSION) +				new_row = readS.readSint16BE(); +			else +				new_row = readS.readByte(); +  			// Set write pointer to the new draw origin  			write_p = buf + ((y_start + new_row) * screen_w) + x_start + x_vector; +			VALIDATE_WRITE_POINTER;  			continue;  			break; -		case 0x30: // Reposition command +		case SAGA_FRAME_REPOSITION: // Reposition command  			x_vector = readS.readSint16BE();  			write_p += x_vector; +			VALIDATE_WRITE_POINTER;  			continue;  			break; -		case 0x3F: // End of frame marker +		case SAGA_FRAME_END: // End of frame marker  			return SUCCESS;  			break;  		default: @@ -530,22 +551,24 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_  		control_ch = mark_byte & 0xC0U;  		param_ch = mark_byte & 0x3FU;  		switch (control_ch) { -		case 0xC0: // 1100 0000 +		case SAGA_FRAME_EMPTY_RUN: // 1100 0000  			// Run of empty pixels  			runcount = param_ch + 1;  			write_p += runcount; +			VALIDATE_WRITE_POINTER;  			continue;  			break; -		case 0x80: // 1000 0000 +		case SAGA_FRAME_COMPRESSED_RUN: // 1000 0000  			// Run of compressed data  			runcount = param_ch + 1;  			data_byte = readS.readByte();  			for (i = 0; i < runcount; i++) {  				*write_p++ = data_byte; +				VALIDATE_WRITE_POINTER;  			}  			continue;  			break; -		case 0x40: // 0100 0000 +		case SAGA_FRAME_UNCOMPRESSED_RUN: // 0100 0000  			// Uncompressed run  			runcount = param_ch + 1;  			for (i = 0; i < runcount; i++) { @@ -554,6 +577,7 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_  					*write_p = data_byte;  				}  				write_p++; +				VALIDATE_WRITE_POINTER;  			}  			continue;  			break; @@ -586,7 +610,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  	size_t in_ch_offset; -	MemoryReadStream readS(thisf_p, thisf_len); +	MemoryReadStreamEndian readS(thisf_p, thisf_len, !IS_BIG_ENDIAN); // RLE has inversion BE<>LE  	byte *outbuf_p = decode_buf;  	byte *outbuf_endp = (decode_buf + decode_buf_len) - 1; @@ -616,13 +640,13 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  					return FAILURE;  				} -				param1 = readS.readUint16BE(); -				param2 = readS.readUint16BE(); +				param1 = readS.readUint16(); +				param2 = readS.readUint16();  				readS.readByte(); // skip 1? -				param3 = readS.readUint16BE(); -				param4 = readS.readUint16BE(); -				param5 = readS.readUint16BE(); -				param6 = readS.readUint16BE(); +				param3 = readS.readUint16(); +				param4 = readS.readUint16(); +				param5 = readS.readUint16(); +				param6 = readS.readUint16();  				x_origin = param1;  				y_origin = param2; @@ -639,8 +663,8 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  				continue;  			}  			break; -		case 0x10: // Long Unencoded Run -			runcount = readS.readSint16BE(); +		case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // Long Unencoded Run +			runcount = readS.readSint16();  			if (thisf_len - readS.pos() < runcount) {  				warning("0x%02X: Input buffer underrun", in_ch);  				return FAILURE; @@ -672,13 +696,13 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  			readS.readByte();  			continue;  			break; -		case 0x20: // Long compressed run +		case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long compressed run  			if (thisf_len - readS.pos() <= 3) {  				warning("0x%02X: Input buffer underrun", in_ch);  				return FAILURE;  			} -			runcount = readS.readSint16BE(); +			runcount = readS.readSint16();  			data_pixel = readS.readByte();  			for (c = 0; c < runcount; c++) { @@ -689,27 +713,27 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  			continue;  			break; -		case 0x2F: // End of row +		case SAGA_FRAME_ROW_END: // End of row  			if (thisf_len - readS.pos() <= 4) {  				return FAILURE;  			} -			x_vector = readS.readSint16BE(); -			new_row = readS.readSint16BE(); +			x_vector = readS.readSint16(); +			new_row = readS.readSint16();  			outbuf_p = decode_buf + ((y_origin + new_row) * di.logical_w) + x_origin + x_vector;  			outbuf_remain = (outbuf_endp - outbuf_p) + 1;  			continue;  			break; -		case 0x30: // Reposition command +		case SAGA_FRAME_REPOSITION: // Reposition command  			if (thisf_len - readS.pos() < 2) {  				return FAILURE;  			} -			x_vector = readS.readSint16BE(); +			x_vector = readS.readSint16();  			if (((x_vector > 0) && ((size_t) x_vector > outbuf_remain)) || (-x_vector > outbuf_p - decode_buf)) { -				warning("0x30: Invalid x_vector"); +				warning("SAGA_FRAME_REPOSITION: Invalid x_vector");  				return FAILURE;  			} @@ -718,8 +742,8 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  			continue;  			break; -		case 0x3F:	// 68: Frame end marker -			debug(1, "0x3F: Frame end marker"); +		case SAGA_FRAME_END:	// Frame end marker +			debug(1, "SAGA_FRAME_END: Frame end marker");  			if (decoded_data && (thisf_len - readS.pos() > 0)) {  				*nextf_p = thisf_p + readS.pos();  				*nextf_len = thisf_len - readS.pos(); @@ -740,7 +764,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  		param_ch = in_ch & 0x3f;  		switch (control_ch) { -		case 0xC0: // Run of empty pixels +		case SAGA_FRAME_EMPTY_RUN: // Run of empty pixels  			runcount = param_ch + 1;  			if (outbuf_remain < runcount) {  				return FAILURE; @@ -750,7 +774,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  			outbuf_remain -= runcount;  			continue;  			break; -		case 0x80: // Run of compressed data +		case SAGA_FRAME_COMPRESSED_RUN: // Run of compressed data  			runcount = param_ch + 1;  			if ((outbuf_remain < runcount) || (thisf_len - readS.pos() <= 1)) {  				return FAILURE; @@ -765,7 +789,7 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *  			outbuf_remain -= runcount;  			continue;  			break; -		case 0x40: // Uncompressed run +		case SAGA_FRAME_UNCOMPRESSED_RUN: // Uncompressed run  			runcount = param_ch + 1;  			if ((outbuf_remain < runcount) || (thisf_len - readS.pos() < runcount)) {  				return FAILURE; @@ -809,12 +833,13 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr  		return FAILURE;  	} -	MemoryReadStream readS(resdata, resdata_len); + +	MemoryReadStreamEndian readS(resdata, resdata_len, IS_BIG_ENDIAN);   	// Read animation header  	ah.magic = readS.readUint16LE(); -	ah.screen_w = readS.readUint16LE(); -	ah.screen_h = readS.readUint16LE(); +	ah.screen_w = readS.readUint16(); +	ah.screen_h = readS.readUint16();  	ah.unknown06 = readS.readByte();  	ah.unknown07 = readS.readByte();  	ah.nframes = readS.readByte(); @@ -828,9 +853,11 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr  		return FAILURE;  	} +	readS._bigEndian = !IS_BIG_ENDIAN; // RLE has inversion BE<>LE +  	for (current_frame = 1; current_frame < find_frame; current_frame++) {  		magic = readS.readByte(); -		if (magic != SAGA_FRAME_HEADER_MAGIC) { +		if (magic != SAGA_FRAME_START) {  			// Frame sync failure. Magic Number not found  			return FAILURE;  		} @@ -839,33 +866,36 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr  		for (i = 0; i < SAGA_FRAME_HEADER_LEN; i++)  			readS.readByte(); +  		// For some strange reason, the animation header is in little  		// endian format, but the actual RLE encoded frame data,   		// including the frame header, is in big endian format. */  		do {  			mark_byte = readS.readByte(); +//			debug(7, "_pos=%x mark_byte=%x", readS.pos(), mark_byte); +  			switch (mark_byte) { -			case 0x3F: // End of frame marker +			case SAGA_FRAME_END: // End of frame marker  				continue;  				break; -			case 0x30: // Reposition command -				readS.readByte(); -				readS.readByte(); +			case SAGA_FRAME_REPOSITION: // Reposition command +				readS.readSint16BE();  				continue;  				break; -			case 0x2F: // End of row marker -				readS.readByte(); -				readS.readByte(); -				readS.readByte(); +			case SAGA_FRAME_ROW_END: // End of row marker +				readS.readSint16BE(); +				if (IS_MAC_VERSION) +					readS.readSint16BE(); +				else +					readS.readByte();  				continue;  				break; -			case 0x20: // Long compressed run marker -				readS.readByte(); -				readS.readByte(); +			case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long compressed run marker +				readS.readSint16BE();  				readS.readByte();  				continue;  				break; -			case 0x10: // (16) 0001 0000 +			case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // (16) 0001 0000  				// Long Uncompressed Run  				runcount = readS.readSint16BE();  				for (i = 0; i < runcount; i++) @@ -879,16 +909,16 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr  			// Mask all but two high order (control) bits  			control = mark_byte & 0xC0;  			switch (control) { -			case 0xC0: +			case SAGA_FRAME_EMPTY_RUN:  				// Run of empty pixels  				continue;  				break; -			case 0x80: +			case SAGA_FRAME_COMPRESSED_RUN:  				// Run of compressed data  				readS.readByte(); // Skip data byte  				continue;  				break; -			case 0x40: +			case SAGA_FRAME_UNCOMPRESSED_RUN:  				// Uncompressed run  				runcount = (mark_byte & 0x3f) + 1;  				for (i = 0; i < runcount; i++) @@ -900,7 +930,7 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr  				return FAILURE;  				break;  			} -		} while (mark_byte != 63); +		} while (mark_byte != SAGA_FRAME_END);  	}  	*frame_offset_p = readS.pos(); | 
