/*
 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2013, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */
 
#include <stdio.h>
 
#include "ValueLocation.h"
 
 
// #pragma mark - ValuePieceLocation
 
 
ValuePieceLocation&
ValuePieceLocation::Normalize(bool bigEndian)
{
	uint64 excessMSBs = bitOffset / 8;
	uint64 excessLSBs = size - (bitOffset + bitSize + 7) / 8;
 
	if (excessMSBs > 0 || excessLSBs > 0) {
		switch (type) {
			case VALUE_PIECE_LOCATION_MEMORY:
				if (bigEndian)
					address += excessMSBs;
				else
					address += excessLSBs;
				bitOffset -= excessMSBs * 8;
				size -= excessMSBs + excessLSBs;
				break;
			case VALUE_PIECE_LOCATION_UNKNOWN:
				bitOffset -= excessMSBs * 8;
				size -= excessMSBs + excessLSBs;
				break;
			case VALUE_PIECE_LOCATION_REGISTER:
			default:
				break;
		}
	}
 
	return *this;
}
 
 
// #pragma mark - ValueLocation
 
 
ValueLocation::ValueLocation()
	:
	fBigEndian(false),
	fWritable(false)
{
}
 
 
ValueLocation::ValueLocation(bool bigEndian)
	:
	fBigEndian(bigEndian),
	fWritable(false)
{
}
 
 
ValueLocation::ValueLocation(bool bigEndian, const ValuePieceLocation& piece)
	:
	fBigEndian(bigEndian)
{
	AddPiece(piece);
}
 
 
ValueLocation::ValueLocation(const ValueLocation& other)
	:
	fPieces(other.fPieces),
	fBigEndian(other.fBigEndian)
{
}
 
 
bool
ValueLocation::SetToByteOffset(const ValueLocation& other, uint64 byteOffset,
	uint64 byteSize)
{
	Clear();
 
	fBigEndian = other.fBigEndian;
	ValuePieceLocation piece = other.PieceAt(0);
	piece.SetToMemory(piece.address + byteOffset);
	piece.SetSize(byteSize);
 
	return AddPiece(piece);
}
 
 
bool
ValueLocation::SetTo(const ValueLocation& other, uint64 bitOffset,
	uint64 bitSize)
{
	Clear();
 
	fBigEndian = other.fBigEndian;
 
	// compute the total bit size
	int32 count = other.CountPieces();
	uint64 totalBitSize = 0;
	for (int32 i = 0; i < count; i++) {
		const ValuePieceLocation &piece = other.PieceAt(i);
		totalBitSize += piece.bitSize;
	}
 
	// adjust requested bit offset/size to something reasonable, if necessary
	if (bitOffset + bitSize > totalBitSize) {
		if (bitOffset >= totalBitSize)
			return true;
		bitSize = totalBitSize - bitOffset;
	}
 
	if (fBigEndian) {
		// Big endian: Skip the superfluous most significant bits, copy the
		// pieces we need (cutting the first and the last one as needed) and
		// ignore the remaining pieces.
 
		// skip pieces for the most significant bits we don't need anymore
		uint64 bitsToSkip = bitOffset;
		int32 i;
		ValuePieceLocation piece;
		for (i = 0; i < count; i++) {
			const ValuePieceLocation& tempPiece = other.PieceAt(i);
			if (tempPiece.bitSize > bitsToSkip) {
				if (!piece.Copy(tempPiece))
					return false;
				break;
			}
			bitsToSkip -= tempPiece.bitSize;
		}
 
		// handle partial piece
		if (bitsToSkip > 0) {
			piece.bitOffset += bitsToSkip;
			piece.bitSize -= bitsToSkip;
			piece.Normalize(fBigEndian);
		}
 
		// handle remaining pieces
		while (bitSize > 0) {
			if (piece.bitSize > bitSize) {
				// the piece is bigger than the remaining size -- cut it
				piece.bitSize = bitSize;
				piece.Normalize(fBigEndian);
				bitSize = 0;
			} else
				bitSize -= piece.bitSize;
 
			if (!AddPiece(piece))
				return false;
 
			if (++i >= count)
				break;
 
			if (!piece.Copy(other.PieceAt(i)))
				return false;
		}
	} else {
		// Little endian: Skip the superfluous least significant bits, copy the
		// pieces we need (cutting the first and the last one as needed) and
		// ignore the remaining pieces.
 
		// skip pieces for the least significant bits we don't need anymore
		uint64 bitsToSkip = totalBitSize - bitOffset - bitSize;
		int32 i;
		ValuePieceLocation piece;
		for (i = 0; i < count; i++) {
			const ValuePieceLocation& tempPiece = other.PieceAt(i);
			if (tempPiece.bitSize > bitsToSkip) {
				if (!piece.Copy(tempPiece))
					return false;
				break;
			}
			bitsToSkip -= piece.bitSize;
		}
 
		// handle partial piece
		if (bitsToSkip > 0) {
			piece.bitSize -= bitsToSkip;
			piece.Normalize(fBigEndian);
		}
 
		// handle remaining pieces
		while (bitSize > 0) {
			if (piece.bitSize > bitSize) {
				// the piece is bigger than the remaining size -- cut it
				piece.bitOffset += piece.bitSize - bitSize;
				piece.bitSize = bitSize;
				piece.Normalize(fBigEndian);
				bitSize = 0;
			} else
				bitSize -= piece.bitSize;
 
			if (!AddPiece(piece))
				return false;
 
			if (++i >= count)
				break;
 
			if (!piece.Copy(other.PieceAt(i)))
				return false;
		}
	}
 
	return true;
}
 
 
void
ValueLocation::Clear()
{
	fWritable = false;
	fPieces.clear();
}
 
 
bool
ValueLocation::AddPiece(const ValuePieceLocation& piece)
{
	// Just add, don't normalize. This allows for using the class with different
	// semantics (e.g. in the DWARF code).
	try {
		fPieces.push_back(piece);
	} catch (...) {
		return false;
	}
 
	if (fPieces.size() == 1)
		fWritable = piece.writable;
	else
		fWritable = fWritable && piece.writable;
 
	return true;
}
 
 
int32
ValueLocation::CountPieces() const
{
	return fPieces.size();
}
 
 
ValuePieceLocation
ValueLocation::PieceAt(int32 index) const
{
	if (index < 0 || index >= (int32)fPieces.size())
		return ValuePieceLocation();
 
	return fPieces[index];
}
 
 
bool
ValueLocation::SetPieceAt(int32 index, const ValuePieceLocation& piece)
{
	if (index < 0 || index >= (int32)fPieces.size())
		return false;
 
	return fPieces[index].Copy(piece);
}
 
 
ValueLocation&
ValueLocation::operator=(const ValueLocation& other)
{
	fPieces = other.fPieces;
	fBigEndian = other.fBigEndian;
	return *this;
}
 
 
void
ValueLocation::Dump() const
{
	int32 count = fPieces.size();
	printf("ValueLocation: %s endian, %" B_PRId32 " pieces:\n",
		fBigEndian ? "big" : "little", count);
 
	for (int32 i = 0; i < count; i++) {
		const ValuePieceLocation& piece = fPieces[i];
		switch (piece.type) {
			case VALUE_PIECE_LOCATION_INVALID:
				printf("  invalid\n");
				continue;
			case VALUE_PIECE_LOCATION_UNKNOWN:
				printf("  unknown");
				break;
			case VALUE_PIECE_LOCATION_MEMORY:
				printf("  address %#" B_PRIx64, piece.address);
				break;
			case VALUE_PIECE_LOCATION_REGISTER:
				printf("  register %" B_PRIu32, piece.reg);
				break;
			case VALUE_PIECE_LOCATION_IMPLICIT:
				printf("  implicit value: ");
				for (uint32 j = 0; j < piece.size; j++)
					printf("%x ", ((char *)piece.value)[j]);
				break;
		}
 
		printf(" size: %" B_PRIu64 " (%" B_PRIu64 " bits), offset: %" B_PRIu64
			" bits\n", piece.size, piece.bitSize, piece.bitOffset);
	}
}

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fWritable.