root/src/kits/debugger/dwarf/DataReader.h
/*
 * 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),
                fIsBigEndian(false),
                fOverflow(false)
        {
        }

        DataReader(const void* data, off_t size, uint8 addressSize, bool isBigEndian)
        {
                SetTo(data, size, addressSize, isBigEndian);
        }

        void SetTo(const void* data, off_t size, uint8 addressSize, bool isBigEndian)
        {
                fData = (const uint8*)data;
                fInitialSize = fSize = size;
                fAddressSize = addressSize;
                fIsBigEndian = isBigEndian;
                fOverflow = false;
        }

        DataReader RestrictedReader()
        {
                return *this;
        }

        DataReader RestrictedReader(off_t maxLength)
        {
                return DataReader(fData, maxLength, fAddressSize, fIsBigEndian);
        }

        DataReader RestrictedReader(off_t relativeOffset, off_t maxLength)
        {
                return DataReader(fData + relativeOffset, maxLength, fAddressSize, fIsBigEndian);
        }

        bool HasData() const
        {
                return fSize > 0;
        }

        uint32 AddressSize() const
        {
                return fAddressSize;
        }

        bool IsBigEndian() const
        {
                return fIsBigEndian;
        }

        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;
        }

        //TODO: take care of host vs target endianness
        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;
        }

        uint64 ReadUInt(size_t numBytes, uint64 defaultValue)
        {
                uint64 result = 0;
                if (fIsBigEndian) {
                        for (size_t i = 0; i < numBytes; i++) {
                                uint8 byte = Read<uint8>(0);
                                result <<= 8;
                                result |= (uint64)byte;
                        }
                } else {
                        int shift = 0;
                        for (size_t i = 0; i < numBytes; i++) {
                                uint8 byte = Read<uint8>(0);
                                result |= (uint64)byte << shift;
                                shift += 8;
                        }
                }

                return fOverflow ? defaultValue : result;
        }

        uint32 ReadU24(uint32 defaultValue)
        {
                return ReadUInt(3, defaultValue);
        }

        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                    fIsBigEndian;
        bool                    fOverflow;
};


#endif  // DATA_READER_H