/*
* File:        DataSource.h
*
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
* See included license file for license details.
*/
#if !defined(_DataSource_h_)
#define _DataSource_h_

#include <vector>
#include "Value.h"
#include "smart_ptr.h"
#include "StExecutableImage.h"

namespace elftosb
{

// Forward declaration
class DataTarget;

/*!
* \brief Abstract base class for data sources.
*
* Data sources represent any sort of data that can be placed or loaded
* into a target region. Sources may be a single blob of data read from
* a file or may consist of many segments.
*
* The three most important features of data sources are:
* - Sources may be multi-segmented.
* - Sources and/or segments can have a "natural" or default target location.
* - The target for a source may be taken into consideration when the source
*              describes itself.
*/
class DataSource
{
public:
       /*!
        * \brief Discrete, contiguous part of the source's data.
        *
        * This class is purely abstract and subclasses of DataSource are expected
        * to subclass it to implement a segment particular to their needs.
        */
       class Segment
       {
       public:
               //! \brief Default constructor.
               Segment(DataSource & source) : m_source(source) {}

               //! \brief Destructor.
               virtual ~Segment() {}

               //! \brief Gets all or a portion of the segment's data.
               //!
               //! The data is copied into \a buffer. Up to \a maxBytes bytes may be
               //! copied, so \a buffer must be at least that large.
               //!
               //! \param offset Index of the first byte to start copying from.
               //! \param maxBytes The maximum number of bytes that can be returned. \a buffer
               //!             must be at least this large.
               //! \param buffer Pointer to buffer where the data is copied.
               //! \return The number of bytes copied into \a buffer.
               virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer)=0;

               //! \brief Gets the length of the segment's data.
               virtual unsigned getLength()=0;

               //! \brief Returns whether the segment has an associated address.
               virtual bool hasNaturalLocation()=0;

               //! \brief Returns the address associated with the segment.
               virtual uint32_t getBaseAddress() { return 0; }

       protected:
               DataSource & m_source;  //!< The data source to which this segment belongs.
       };

       /*!
        * \brief This is a special type of segment containing a repeating pattern.
        *
        * By default the segment doesn't have a specific length or data. The length depends
        * on the target's address range. And the data is just the pattern, repeated
        * many times. In addition, pattern segments do not have a natural location.
        *
        * Calling code should look for instances of PatternSegment and handle them
        * as special cases that can be optimized.
        */
       class PatternSegment : public Segment
       {
       public:
               //! \brief Default constructor.
               PatternSegment(DataSource & source);

               //! \brief Constructor taking a fill pattern.
               PatternSegment(DataSource & source, const SizedIntegerValue & pattern);

               //! \brief Constructor taking a byte fill pattern.
               PatternSegment(DataSource & source, uint8_t pattern);

               //! \brief Constructor taking a half-word fill pattern.
               PatternSegment(DataSource & source, uint16_t pattern);

               //! \brief Constructor taking a word fill pattern.
               PatternSegment(DataSource & source, uint32_t pattern);

               //! \name Segment methods
               //@{
               //! \brief Pattern segments have no natural address.
               virtual bool hasNaturalLocation() { return false; }

               //! \brief Performs a pattern fill into the \a buffer.
               virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);

               //! \brief Returns a length based on the data target's address range.
               virtual unsigned getLength();
               //@}

               //! \name Pattern accessors
               //@{
               //! \brief Assigns a new fill pattern.
               inline void setPattern(const SizedIntegerValue & newPattern) { m_pattern = newPattern; }

               //! \brief Return the fill pattern for the segment.
               inline SizedIntegerValue & getPattern() { return m_pattern; }

               //! \brief Assignment operator, sets the pattern value and length.
               PatternSegment & operator = (const SizedIntegerValue & value) { m_pattern = value; return *this; }
               //@}

       protected:
               SizedIntegerValue m_pattern;    //!< The fill pattern.
       };

public:
       //! \brief Default constructor.
       DataSource() : m_target(0) {}

       //! \brief Destructor.
       virtual ~DataSource() {}

       //! \name Data target
       //@{
       //! \brief Sets the associated data target.
       inline void setTarget(DataTarget * target) { m_target = target; }

       //! \brief Gets the associated data target.
       inline DataTarget * getTarget() const { return m_target; }
       //@}

       //! \name Segments
       //@{
       //! \brief Returns the number of segments in this data source.
       virtual unsigned getSegmentCount()=0;

       //! \brief Returns segment number \a index of the data source.
       virtual Segment * getSegmentAt(unsigned index)=0;
       //@}

protected:
       DataTarget * m_target;  //!< Corresponding target for this source.
};

/*!
* \brief Data source for a repeating pattern.
*
* The pattern is represented by a SizedIntegerValue object. Thus the pattern
* can be either byte, half-word, or word sized.
*
* This data source has only one segment, and the PatternSource instance acts
* as its own single segment.
*/
class PatternSource : public DataSource, public DataSource::PatternSegment
{
public:
       //! \brief Default constructor.
       PatternSource();

       //! \brief Constructor taking the pattern value.
       PatternSource(const SizedIntegerValue & value);

       //! \brief There is only one segment.
       virtual unsigned getSegmentCount() { return 1; }

       //! \brief Returns this object, as it is its own segment.
       virtual DataSource::Segment * getSegmentAt(unsigned index) { return this; }

       //! \brief Assignment operator, sets the pattern value and length.
       PatternSource & operator = (const SizedIntegerValue & value) { setPattern(value); return *this; }
};

/*!
* \brief Data source for data that is not memory mapped (has no natural address).
*
* This data source can only manage a single block of data, which has no
* associated address. It acts as its own Segment.
*/
class UnmappedDataSource : public DataSource, public DataSource::Segment
{
public:
       //! \brief Default constructor.
       UnmappedDataSource();

       //! \brief Constructor taking the data, which is copied.
       UnmappedDataSource(const uint8_t * data, unsigned length);

       //! \brief Sets the source's data.
       void setData(const uint8_t * data, unsigned length);

       //! \brief There is only one segment.
       virtual unsigned getSegmentCount() { return 1; }

       //! \brief Returns this object, as it is its own segment.
       virtual DataSource::Segment * getSegmentAt(unsigned index) { return this; }

       //! \name Segment methods
       //@{
       //! \brief Unmapped data sources have no natural address.
       virtual bool hasNaturalLocation() { return false; }

       //! \brief Copies a portion of the data into \a buffer.
       virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);

       //! \brief Returns the number of bytes of data managed by the source.
       virtual unsigned getLength() { return m_length; }
       //@}

protected:
       smart_array_ptr<uint8_t> m_data;        //!< The data.
       unsigned m_length;      //!< Byte count of the data.
};

/*!
* \brief Data source that takes its data from an executable image.
*
* \see StExecutableImage
*/
class MemoryImageDataSource : public DataSource
{
public:
       //! \brief Default constructor.
       MemoryImageDataSource(StExecutableImage * image);

       //! \brief Destructor.
       virtual ~MemoryImageDataSource();

       //! \brief Returns the number of memory regions in the image.
       virtual unsigned getSegmentCount();

       //! \brief Returns the data source segment at position \a index.
       virtual DataSource::Segment * getSegmentAt(unsigned index);

protected:
       /*!
        * \brief Segment corresponding to a text region of the executable image.
        */
       class TextSegment : public DataSource::Segment
       {
       public:
               //! \brief Default constructor
               TextSegment(MemoryImageDataSource & source, StExecutableImage * image, unsigned index);

               virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t * buffer);
               virtual unsigned getLength();

               virtual bool hasNaturalLocation() { return true; }
               virtual uint32_t getBaseAddress();

       protected:
               StExecutableImage * m_image;    //!< Coalesced image of the file.
               unsigned m_index;       //!< Record index.
       };

       /*!
        * \brief Segment corresponding to a fill region of the executable image.
        */
       class FillSegment : public DataSource::PatternSegment
       {
       public:
               FillSegment(MemoryImageDataSource & source, StExecutableImage * image, unsigned index);

               virtual unsigned getLength();

               virtual bool hasNaturalLocation() { return true; }
               virtual uint32_t getBaseAddress();

       protected:
               StExecutableImage * m_image;    //!< Coalesced image of the file.
               unsigned m_index;       //!< Record index.
       };

protected:
       StExecutableImage * m_image;    //!< The memory image that is the data source.

       typedef std::vector<DataSource::Segment*> segment_array_t;      //!< An array of segments.
       segment_array_t m_segments;     //!< The array of Segment instances.
};

}; // namespace elftosb

#endif // _DataSource_h_