/*
 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef DATA_READER_H
#define DATA_READER_H
 
 
#include <string.h>
 
#include "Types.h"
 
 
class DataReader {
public:
	DataReader()
		:
		fData(NULL),
		fSize(0),
		fInitialSize(0),
		fAddressSize(4),
		fOverflow(false)
	{
	}
 
	DataReader(const void* data, off_t size, uint8 addressSize)
	{
		SetTo(data, size, addressSize);
	}
 
	void SetTo(const void* data, off_t size, uint8 addressSize)
	{
		fData = (const uint8*)data;
		fInitialSize = fSize = size;
		fAddressSize = addressSize;
		fOverflow = false;
	}
 
	DataReader RestrictedReader()
	{
		return *this;
	}
 
	DataReader RestrictedReader(off_t maxLength)
	{
		return DataReader(fData, maxLength, fAddressSize);
	}
 
	DataReader RestrictedReader(off_t relativeOffset, off_t maxLength)
	{
		return DataReader(fData + relativeOffset, maxLength, fAddressSize);
	}
 
	bool HasData() const
	{
		return fSize > 0;
	}
 
	uint32 AddressSize() const
	{
		return fAddressSize;
	}
 
	void SetAddressSize(uint8 addressSize)
	{
		fAddressSize = addressSize;
	}
 
	bool HasOverflow() const
	{
		return fOverflow;
	}
 
	const void* Data() const
	{
		return fData;
	}
 
	off_t BytesRemaining() const
	{
		return fSize;
	}
 
	off_t Offset() const
	{
		return fInitialSize - fSize;
	}
 
	void SeekAbsolute(off_t offset)
	{
		if (offset < 0)
			offset = 0;
		else if (offset > fInitialSize)
			offset = fInitialSize;
 
		fData += offset - Offset();
		fSize = fInitialSize - offset;
	}
 
	template<typename Type>
	Type Read(const Type& defaultValue)
	{
		if (fSize < (off_t)sizeof(Type)) {
			fOverflow = true;
			fSize = 0;
			return defaultValue;
		}
 
		Type data;
		memcpy(&data, fData, sizeof(Type));
 
		fData += sizeof(Type);
		fSize -= sizeof(Type);
 
		return data;
	}
 
	target_addr_t ReadAddress(target_addr_t defaultValue)
	{
		return fAddressSize == 4
			? (target_addr_t)Read<uint32>(defaultValue)
			: (target_addr_t)Read<uint64>(defaultValue);
	}
 
	uint64 ReadUnsignedLEB128(uint64 defaultValue)
	{
		uint64 result = 0;
		int shift = 0;
		while (true) {
			uint8 byte = Read<uint8>(0);
			result |= uint64(byte & 0x7f) << shift;
			if ((byte & 0x80) == 0)
				break;
			shift += 7;
		}
 
		return fOverflow ? defaultValue : result;
	}
 
	int64 ReadSignedLEB128(int64 defaultValue)
	{
		int64 result = 0;
		int shift = 0;
		while (true) {
			uint8 byte = Read<uint8>(0);
			result |= uint64(byte & 0x7f) << shift;
			shift += 7;
 
			if ((byte & 0x80) == 0) {
				// sign extend
				if ((byte & 0x40) != 0 && shift < 64)
					result |= -((uint64)1 << shift);
				break;
			}
		}
 
		return fOverflow ? defaultValue : result;
	}
 
	const char* ReadString()
	{
		const char* string = (const char*)fData;
		while (fSize > 0) {
			fData++;
			fSize--;
 
			if (fData[-1] == 0)
				return string;
		}
 
		fOverflow = true;
		return NULL;
	}
 
	uint64 ReadInitialLength(bool& _dwarf64)
	{
		uint64 length = Read<uint32>(0);
		_dwarf64 = (length == 0xffffffff);
		if (_dwarf64)
			length = Read<uint64>(0);
		return length;
	}
 
	bool Skip(off_t bytes)
	{
		if (bytes < 0)
			return false;
 
		if (bytes > fSize) {
			fSize = 0;
			fOverflow = true;
			return false;
		}
 
		fData += bytes;
		fSize -= bytes;
 
		return true;
	}
 
private:
	const uint8*	fData;
	off_t			fSize;
	off_t			fInitialSize;
	uint8			fAddressSize;
	bool			fOverflow;
};
 
 
#endif	// DATA_READER_H

V598 The 'memcpy' function is used to copy the fields of 'Type' class. Virtual table pointer will be damaged by this.