/*
 * xlat.c
 *
 * Translate
 */
#include "decoder.h"


void NEAR init_decoder_translation(t_decoder_context *context)
{
	context->dec_instr_pos = 0;
}


#ifdef ASM_TRANSLATE_E8
ulong asm_decoder_translate_e8(ulong instr_pos, ulong file_size, byte *mem, long bytes);

void NEAR decoder_translate_e8(t_decoder_context *context, byte *mem, long bytes)
{
	/*
	 * We don't want the ASM code to have to worry about where in the
	 * context structure a particular element is
	 */
	context->dec_instr_pos = asm_decoder_translate_e8(
		context->dec_instr_pos, 
		context->dec_current_file_size,
		mem, 
		bytes
	);
}

#else /* !ASM_TRANSLATE_E8 */

void NEAR decoder_translate_e8(t_decoder_context *context, byte *mem, long bytes)
{
	ulong   end_instr_pos;
	byte    temp[6];
	byte    *mem_backup;

	if (bytes <= 6)
	{
		context->dec_instr_pos += bytes;
		return;
	}

	mem_backup = mem;

	/* backup these bytes */
	memcpy(temp, &mem[bytes-6], 6);

	/* overwrite them with 0xE8 */
	memset(&mem[bytes-6], 0xE8, 6);

	end_instr_pos = context->dec_instr_pos + bytes - 6;

	while (1)
	{
		unsigned long   absolute;
#if !defined(_X86_)
		unsigned long   offset;
#endif

		/*
		 * We are guaranteed to hit one of the 6 0xE8's we stuck at the
		 * end of the buffer, even if we ran into some corrupted data
		 * that resulted in our jumping over 5 bytes due to a translation
		 */
		while (*mem++ != 0xE8)
			context->dec_instr_pos++;

		if (context->dec_instr_pos >= end_instr_pos)
			break;

		/*
		 * There are 5 or more bytes in the buffer
		 * (i.e. E8 xx xx xx xx)
		 *
		 * We have a complete offset available to (potentially) translate
		 */

#if defined(_X86_)
		absolute = *(ulong *) mem;
#else
        absolute =  ( (ulong)mem[0])     | 
					(((ulong)mem[1])<<8) | 
                    (((ulong)mem[2])<<16)|  
					(((ulong)mem[3])<<24);
#endif

		if (absolute < context->dec_current_file_size)
		{
			/* absolute >= 0 && absolute < dec_current_file_size */

#if defined(_X86_)
			*(ulong *) mem = absolute - context->dec_instr_pos;
#else
			offset = absolute - context->dec_instr_pos;
			mem[0] = (byte) (offset & 255);
			mem[1] = (byte) ((offset >> 8) & 255);
			mem[2] = (byte) ((offset >> 16) & 255);
			mem[3] = (byte) ((offset >> 24) & 255);
#endif
		}
        else if ((ulong) (-(long) absolute) <= context->dec_instr_pos)
		{
            /* absolute >= -instr_pos && absolute < 0 */

#if defined(_X86_)
			*(ulong *) mem = absolute + context->dec_current_file_size;
#else
			offset = absolute + context->dec_current_file_size;
			mem[0] = (byte) (offset & 255);
			mem[1] = (byte) (offset >> 8) & 255;
			mem[2] = (byte) (offset >> 16) & 255;
			mem[3] = (byte) (offset >> 24) & 255;
#endif
		}

		mem += 4;
		context->dec_instr_pos += 5;
	}

	context->dec_instr_pos = end_instr_pos + 6;

	/* restore these bytes */
	memcpy(&mem_backup[bytes-6], temp, 6);
}
#endif