/*******************************************************************************
* intelhexclass - class definitions                                            *
*                                                                              *
* A class to handle the encoding and decoding of an Intel HEX format file as   *
* generated by many tool chains for embedded processors and microcontrollers.  *
*                                                                              *
* This class is constructed based upon the definition given in the document    *
* 'Hexadecimal Object File Format Specification', Revision A, January 6, 1988, *
* © 1998 Intel Corporation                                                     *
*------------------------------------------------------------------------------*
* class intelhex                                                               *
*   Member Functions:                                                          *
*                                                                              *
*******************************************************************************/

/******************************************************************************/
/*! \file intelhexclass.h
* \author Stuart Cording aka CODINGHEAD
*
* A class to handle the encoding, decoding and manipulatio of an Intel HEX
* format file as generated by many tool chains for embedded processors and
* microcontrollers.
*
* This class is constructed based upon the definition given in the document
* 'Hexadecimal Object File Format Specification', Revision A, January 6, 1988,
* © 1998 Intel Corporation.
********************************************************************************
* \note See the git versioning notes for version information
*
*******************************************************************************/

/*******************************************************************************
*
*                            INTEL HEX CLASS MODULE
*
*******************************************************************************/

#ifndef INTELHEXCLASS_MODULE_PRESENT__
#define INTELHEXCLASS_MODULE_PRESENT__

/*******************************************************************************
*                                 INCLUDE FILES
*******************************************************************************/
#include <iostream>
#include <map>
#include <list>

/*******************************************************************************
*                                    EXTERNS
*******************************************************************************/


/*******************************************************************************
*                             DEFAULT CONFIGURATION
*******************************************************************************/


/*******************************************************************************
*                                    DEFINES
*******************************************************************************/

using namespace std;

/******************************************************************************/
/*! \cond
* class - intelhex
* \endcond
*
* \brief Class to decode, encode and manipulate Intel HEX format files.
*
* The Intel HEX class allows the user to stream in the content of an Intel HEX
* file so that its content can by analysed more easily than trying to decode
* the Intel HEX file in a text editor. In conjunction with a suitable
* application it is possible to create content, analyse content and even compare
* the content of files with one another.
*******************************************************************************/
class intelhex {
  /**********************************************************************/
  /*! \brief Output stream overload operator.
  *
  * Operator overloaded to encode any data held in memory into the Intel
  * HEX format for storage on disk
  *
  * \sa operator>>()
  *
  * \param dataOut    - Output stream for to store the decoded file
  *                     information
  * \param ihLocal    - Points to this class so that friend function has
  *                     access to private class members
  *
  * \retval           - pointer to output stream
  ***********************************************************************/
  friend ostream& operator<<(ostream& dataOut,
                             intelhex& ihLocal);

  /**********************************************************************/
  /*! \brief Input stream overload operator.
  *
  * Operator overloaded to decode data streamed in from a file in the
  * Intel HEX format into memory
  *
  * \sa operator<<()
  *
  * \param dataIn     - Input stream for the encoded file information
  * \param ihLocal    - Points to this class so that friend function has
  *                     access to private class members
  *
  * \retval           - pointer to input stream
  ***********************************************************************/
  friend istream& operator>>(istream& dataIn,
                             intelhex& ihLocal);

 private:
  /**********************************************************************/
  /*! \brief Container for decoded Intel HEX content.
  *
  * STL map holding the addresses found in the Intel HEX file and the
  * associated data byte stored at that address
  ***********************************************************************/
  map<unsigned long, unsigned char> ihContent;

  /**********************************************************************/
  /*! \brief Iterator for the container holding the decoded Intel HEX
  *        content.
  *
  * This iterator is used by the class to point to the location in memory
  * currently being used to read or write data. If no file has been
  * loaded into memory, it points to the start of ihContent.
  ***********************************************************************/
  map<unsigned long, unsigned char>::iterator ihIterator;

  /**********************************************************************/
  /*! \brief Pair for the container holding the decoded Intel HEX content.
  *
  * This is used to acquire the result of an attempt to insert new data
  * into ihContent. Since the ihContent is a map STL, it can't allow
  * data to be assigned to the same address more than once. In this way we
  * can ensure that no address in a file is falsely assigned data more
  * than once.
  ***********************************************************************/
  pair<map<unsigned long, unsigned char>::iterator,bool> ihReturn;

  /**********************************************************************/
  /*! \brief Stores segment base address of Intel HEX file.
  *
  * The segment base address is a 32-bit address to which the current
  * load offset (as found in a Data Record line of the Intel HEX file) is
  * added to calculate the actual address of the data. The Data Records
  * can only point to a 64kByte address, so the segment base address
  * expands the addressing to 4GB. This variable always holds the last
  * address accessed. This variable is only used during file decoding
  * and encoding in the operator<< and operator>> class member friend
  * functions.
  ***********************************************************************/
  unsigned long segmentBaseAddress;

  /**********************************************************************/
  /*! \brief Stores the content of the CS/IP Registers, if used.
  *
  * Used to store the content of the CS and IS Register for HEX files
  * created for x286 or earlier Intel processors. This information is
  * retrieved from the Start Segment Address Record or can be defined
  * by the user using the setStartSegmentAddress() function.
  * The found element defines if these registers hold valid data or not.
  *
  * \param    csRegister  - content of the CS register
  * \param    ipRegister  - content of the IP register
  * \param    exists      - defines if values for the above registers have
  *                         been written (true) or not (false)
  *
  * \sa getStartSegmentAddress(), setStartSegmentAddress()
  ***********************************************************************/
  struct {
    unsigned short  csRegister;
    unsigned short  ipRegister;
    bool            exists;
  } startSegmentAddress;

  /**********************************************************************/
  /*! \brief Stores the content of the EIP Register, if used.
  *
  * Used to store the content of the EIP Register for HEX files created
  * for x386 Intel processors. This information is retrieved from the
  * the Start Linear Address Record or can be defined by using the
  * setStartLinearAddress() function.
  * The found element defines if this register holds valid data or not.
  *
  * \param    eipRegister - content of the EIP register
  * \param    exists      - defines if a value for the above register has
  *                         been written (true) or not (false)
  *
  * \sa getStartLinearAddress(), setStartLinearAddress()
  ***********************************************************************/
  struct {
    unsigned long   eipRegister;
    bool            exists;
  } startLinearAddress;


  /**********************************************************************/
  /*! \brief Structure to hold warning messages.
  *
  * Holds warning messages generated during encoding/decoding process and
  * number of messages currently present in system
  *
  * \param    ihWarnings      - list of warning messages as strings
  * \param    noOfWarnings    - no of warning messages still present in
  *                             the list
  ***********************************************************************/
  struct {
    list<string> ihWarnings;
    unsigned long noOfWarnings;
  } msgWarning;

  /**********************************************************************/
  /*! \brief Structure to hold error messages.
  *
  * Holds error messages generated during encoding/decoding process and
  * number of messages currently present in system
  *
  * \param    ihErrors        - list of error messages as strings
  * \param    noOferrors      - no of error messages still present in the
  *                             list
  ***********************************************************************/
  struct {
    list<string> ihErrors;
    unsigned long noOfErrors;
  } msgError;

  /**********************************************************************/
  /*! \brief Note that EOF record is found.
  *
  * Used to note that the EOF record was found in order to ensure that it
  * doesn't appear twice during encoding.
  ***********************************************************************/
  bool foundEof;

  /**********************************************************************/
  /*! \brief Select verbose mode.
  *
  * Used during development to display messages as the incoming data
  * stream is decoded
  ***********************************************************************/
  bool verbose;

  /**********************************************************************/
  /*! \brief Select segment address mode.
  *
  * If true, use the segment addressing mode when encoding files.
  * otherwise the default linear address mode will be used. Please refer
  * to Intel's Hexadecimal Object File Format Specifiation for further
  * information.
  ***********************************************************************/
  bool segmentAddressMode;

  /***********************************************************************
  * \brief Converts a 2 char string to its HEX value.
  *
  * Converts a two byte string to its equivalent value in hexadecimal
  *
  * \param        value   - a two character, valid ASCII representation of
  *                         a hexadecimal value
  *
  * \retval       'value' valid   - 8-bit value
  * \retval       'value' invalid - 0x00 and calls addWarning()
  *
  * \note
  * This function will post a warning message using the warning handling
  * system addWarning() if:
  *   -# The string contains anything other that exactly two characters
  *   -# The string contains anything other than the characters 0-9, a-f
  *      and A-F
  *
  * \sa ulToHexString(), ucToHexString(), ulToString()
  ***********************************************************************/
  unsigned char stringToHex(string value);

  /***********************************************************************
  * \brief Converts an unsigned long to a string in HEX format.
  *
  * Takes the received paramter and converts it into its equivalent value
  * represented in ASCII and formatted in hexadecimal. Return value is an
  * 8 character long string, prefaced with '0's where necessary.
  *
  * \param        value   - a value between 0x0000000 and 0xFFFFFFFF
  *
  * \retval               - 8-character long string
  *
  * \note
  * Alpha characters are capitalised.
  *
  * \sa
  * stringToHex(), ucToHexString(), ulToString()
  ***********************************************************************/
  string ulToHexString(unsigned long value);

  /**********************************************************************/
  /*! \brief Converts an unsigned char to a string in HEX format.
  *
  * Takes the received paramter and converts it into its equivalent value
  * represented in ASCII and formatted in hexadecimal. Return value is a
  * 2 character long string, prefaced with '0' where necessary.
  *
  * \param        value   - a value between 0x00 and 0xFF
  *
  * \retval               - 2-character long string
  *
  * \note
  * Alpha characters are capitalised.
  *
  * \sa
  * stringToHex(), ulToHexString(), ulToString()
  ***********************************************************************/
  string ucToHexString(unsigned char value);

  /**********************************************************************/
  /*! \brief Converts an unsigned long to a string in DEC format.
  *
  * Takes the received paramter and converts it into its equivalent value
  * represented in ASCII and formatted in decimal. Return value will never
  * be longer than a 48 character long string.
  *
  * \param        value   - value to be converted
  *
  * \retval               - ASCII string representation of value
  *
  * \sa
  * stringToHex(), ulToHexString(), ucToHexString()
  ***********************************************************************/
  string ulToString(unsigned long value);

  /**********************************************************************/
  /*! \brief Decodes the data content of a data record.
  *
  * Takes the data element of a data record in string format, converts
  * each 2 char element into a single byte and then inserts that byte of
  * data into the ihContent STL map.
  *
  * \sa encodeDataRecord()
  *
  * \param recordLength   - Number of bytes in this record as extracted
  *                         from this line in the Intel HEX file
  * \param loadOffset     - The offset from the segment base address for
  *                         the first byte in this record
  * \param data           - The data content of the record in a string
  ***********************************************************************/
  void decodeDataRecord(unsigned char recordLength,
                        unsigned long loadOffset,
                        string::const_iterator data);

  /**********************************************************************/
  /*! \brief Add a warning message to the warning message list.
  *
  *
  * \param    warningMessage - the text to be added for this warning
  ***********************************************************************/
  void addWarning(string warningMessage);

  /**********************************************************************/
  /*! \brief Add an error message to the error message list.
  *
  * \param    errorMessage - the text to be added for this error
  ***********************************************************************/
  void addError(string errorMessage);

 public:
  /**********************************************************************/
  /*! \brief intelhex Class Constructor.
  *
  * Important initialisation steps performed here:
  * - clear segment base address to zero
  * - clear all x86 start address registers to zero
  * - note that there are, as yet, no errors or warnings
  * - note that the EOF record has not yet been found
  * - set verbode mode to 'false' (default)
  * - initialise class ihIterator
  ***********************************************************************/
  intelhex()
  {
    /* Initialise the segment base address to zero                    */
    segmentBaseAddress = 0;
    /* Clear content of register variables used with the 'Start Segment'
    *  and 'Start Linear' address records                             */
    startSegmentAddress.ipRegister = 0;
    startSegmentAddress.csRegister = 0;
    startSegmentAddress.exists = false;
    startLinearAddress.eipRegister = 0;
    startLinearAddress.exists = false;
    /* Set up error and warning handling variables                    */
    msgWarning.noOfWarnings = 0;
    msgError.noOfErrors = 0;
    /* Note that the EOF record has not been found yet                */
    foundEof = false;
    /* Set verbose mode to off                                        */
    verbose = false;
    /* Set segment address mode to false (default)                    */
    segmentAddressMode = false;
    /* Ensure ihContent is cleared and point ihIterator at it         */
    ihContent.clear();
    ihContent.begin();
    ihIterator = ihContent.begin();
  }

  /**********************************************************************/
  /*! \brief intelhex Class Deconstructor.
  *
  * Currently the deconstructor is intentially empty.
  ***********************************************************************/
  ~intelhex()
  {
    /* Currently nothing */
  }

  /**********************************************************************/
  /*! \brief intelhex Class Copy Constructor.
  *
  * Copy constructor copies all essential elements for the class.
  ***********************************************************************/
  intelhex(const intelhex &ihSource)
  {
    /* Initialise the segment base address                            */
    segmentBaseAddress = ihSource.segmentBaseAddress;
    /* Initialise content of register variables used with the 'Start Segment'
    *  and 'Start Linear' address records                             */
    startSegmentAddress.ipRegister = ihSource.startSegmentAddress.ipRegister;
    startSegmentAddress.csRegister = ihSource.startSegmentAddress.csRegister;
    startSegmentAddress.exists = ihSource.startSegmentAddress.exists;
    startLinearAddress.eipRegister = ihSource.startLinearAddress.eipRegister;
    startLinearAddress.exists = ihSource.startLinearAddress.exists;
    /* Set up error and warning handling variables                    */
    msgWarning.noOfWarnings = ihSource.msgWarning.noOfWarnings;
    msgWarning.ihWarnings = ihSource.msgWarning.ihWarnings;
    msgError.noOfErrors = ihSource.msgError.noOfErrors;
    msgError.ihErrors = ihSource.msgError.ihErrors;
    /* Note that the EOF record has not been found yet                */
    foundEof = ihSource.foundEof;
    /* Set verbose mode to off                                        */
    verbose = ihSource.verbose;
    /* Set segment address mode to false (default)                    */
    segmentAddressMode = ihSource.segmentAddressMode;
    /* Copy HEX file content variables                                */
    ihContent = ihSource.ihContent;
    ihIterator = ihSource.ihIterator;
  }

  /**********************************************************************/
  /*! \brief intelhex Class Assignment Operator.
  *
  * Implements the assignment operator so that the content of the Intel
  * HEX file in memory can be copied to another 'intelhex' variable.
  * You may want to keep a copy of the original data in memory and
  * only manipulate a copy.
  *
  * \param    ihSource    - intelhex variable to be assigned to new
  *                         variable
  *
  * \retval   pointer to variable to which value is to be assigned
  ***********************************************************************/
  intelhex& operator= (const intelhex &ihSource)
  {
    /* Check that we are not trying to assign ourself to ourself      */
    /* i.e. are the source/destination addresses the same like        */
    /* myData = myData;                                               */
    if (this == &ihSource)
      return *this;

    /* Initialise the segment base address                            */
    segmentBaseAddress = ihSource.segmentBaseAddress;
    /* Initialise content of register variables used with the 'Start Segment'
    *  and 'Start Linear' address records                             */
    startSegmentAddress.ipRegister = ihSource.startSegmentAddress.ipRegister;
    startSegmentAddress.csRegister = ihSource.startSegmentAddress.csRegister;
    startSegmentAddress.exists = ihSource.startSegmentAddress.exists;
    startLinearAddress.eipRegister = ihSource.startLinearAddress.eipRegister;
    startLinearAddress.exists = ihSource.startLinearAddress.exists;
    /* Set up error and warning handling variables                    */
    msgWarning.noOfWarnings = ihSource.msgWarning.noOfWarnings;
    msgWarning.ihWarnings = ihSource.msgWarning.ihWarnings;
    msgError.noOfErrors = ihSource.msgError.noOfErrors;
    msgError.ihErrors = ihSource.msgError.ihErrors;
    /* Note that the EOF record has not been found yet                */
    foundEof = ihSource.foundEof;
    /* Set verbose mode to off                                        */
    verbose = ihSource.verbose;
    /* Set segment address mode to false (default)                    */
    segmentAddressMode = ihSource.segmentAddressMode;
    /* Copy HEX file content variables                                */
    ihContent = ihSource.ihContent;
    ihIterator = ihSource.ihIterator;

    return *this;
  }

  /**********************************************************************/
  /*! \brief Overloaded prefix increment operator
  *
  * Overloads the prefix increment operator to move interal iterator to
  * next entry in the ihContent map
  *
  ***********************************************************************/
  intelhex& operator++()
  {
    ++ihIterator;

    return(*this);
  }

  /**********************************************************************/
  /*! \brief Overloaded postfix increment operator
  *
  * Overloads the postfix increment operator to move interal iterator to
  * next entry in the ihContent map
  *
  ***********************************************************************/
  const intelhex operator++(int)
  {
    intelhex tmp(*this);
    ++(*this);
    return(tmp);
  }

  /**********************************************************************/
  /*! \brief Overloaded prefix decrement operator
  *
  * Overloads the prefix decrement operator to move interal iterator to
  * previous entry in the ihContent map
  *
  ***********************************************************************/
  intelhex& operator--()
  {
    --ihIterator;

    return(*this);
  }

  /**********************************************************************/
  /*! \brief Overloaded postfix decrement operator
  *
  * Overloads the postfix decrement operator to move interal iterator to
  * previous entry in the ihContent map
  *
  ***********************************************************************/
  const intelhex operator--(int)
  {
    intelhex tmp(*this);
    --(*this);
    return(tmp);
  }

  /**********************************************************************/
  /*! \brief Moves the address pointer to the first available address.
  *
  * The address pointer will be moved to the first available address in
  * memory of the decoded file or of the data the user has inserted into
  * memory for the purpose of encoding into the Intel HEX format.
  *
  * \sa end()
  *
  * \note This function has no effect if no file has been as yet decoded
  * and no data has been inserted into memory.
  ***********************************************************************/
  void begin()
  {
    if (ihContent.size() != 0)
    {
      ihIterator = ihContent.begin();
    }
  }

  /**********************************************************************/
  /*! \brief Moves the address pointer to the last available address.
  *
  * The address pointer will be moved to the last available address in
  * memory of the decoded file or of the data the user has inserted into
  * memory for the purpose of encoding into the Intel HEX format.
  *
  * \sa begin()
  *
  * \note This function has no effect if no file has been as yet decoded
  * and no data has been inserted into memory.
  ***********************************************************************/
  void end()
  {
    if (!ihContent.empty())
    {
      ihIterator = ihContent.end();
      --ihIterator;
    }
  }

  /**********************************************************************/
  /*! \brief Returns current size of decoded file
  *
  * The quantity of bytes decoded thus far is returned.
  ***********************************************************************/
  unsigned long size()
  {
    return static_cast<unsigned long>(ihContent.size());
  }

  /**********************************************************************/
  /*! \brief Checks if we have reached end of available data
  *
  * The internal pointer is checked to see if we have reached the end of
  * the data held in memory
  *
  * \retval true  - reached the end of the Intel HEX data in memory or no
  *                 data in memory yet.
  * \retval false - end of Intel HEX data in memory not yet reached.
  ***********************************************************************/
  bool endOfData()
  {
    /* Return true if there is no data anyway                         */
    bool result = true;

    if (!ihContent.empty())
    {
      map<unsigned long, unsigned char>::iterator it \
                    = ihContent.end();

      --it;

      if (it != ihIterator)
      {
        result = false;
      }
    }
    return result;
  }

  /**********************************************************************/
  /*! \brief Indicates if the container for data is empty or not
  *
  * The map container is checked for content.
  *
  * \retval true  - the container is empty - no data has been extracted.
  * \retval false - there is data in the container.
  ***********************************************************************/
  bool empty()
  {
    return ihContent.empty();
  }

  /**********************************************************************/
  /*! \brief Moves the address pointer to the desired address.
  *
  * Address pointer will take on the requested address if the address
  * exists in the data stored in memory. If not, the address pointer does
  * not change.
  *
  * \sa currentAddress()
  *
  * \param address    - Desired new address for the address pointer
  *
  * \retval true      - Address exists; pointer moved successfully
  * \retval false     - Address did not exist; pointer not moved
  ***********************************************************************/
  bool jumpTo(unsigned long address)
  {
    bool result = false;

    if (ihContent.size() != 0)
    {
      map<unsigned long, unsigned char>::iterator it;
      it = ihContent.find(address);
      if (it != ihContent.end())
      {
        result = true;
        ihIterator = it;
      }
    }
    return result;
  }

  /**********************************************************************/
  /*! \brief Increments to next piece of data.
  *
  * Address pointer will take on the address of the next location for
  * which there is data.
  *
  * \sa decrementAddress()
  *
  * \retval true  - pointer was incremented; a new data value was found
  * \retval false - end of available data reached; pointer is unchanged
  ***********************************************************************/
  bool incrementAddress()
  {
    bool result = false;

    /* If we have data */
    if (ihContent.size() != 0)
    {
      /* If we're not already pointing to the end */
      if (ihIterator != ihContent.end())
      {
        /* Increment iterator */
        ihIterator++;

        /* If we still haven't reached the end... */
        if (ihIterator != ihContent.end())
        {
          /* Everything is ok! */
          result = true;
        }
      }
    }

    /* If incrementation of the iterator was successful, return true  */
    return result;
  }

  /**********************************************************************/
  /*! \brief Decrements to next piece of data.
  *
  * Address pointer will take on the address of the previous location for
  * which there is data.
  *
  * \sa incrementAddress()
  *
  * \retval true  - pointer was decremented; a new data value was found
  * \retval false - start of available data reached; pointer is unchanged
  ***********************************************************************/
  bool decrementAddress()
  {
    bool result = false;

    /* If we have data */
    if (ihContent.size() != 0)
    {
      /* If we're not already pointing to the start */
      if (ihIterator != ihContent.begin())
      {
        /* Decrement iterator */
        ihIterator--;

        /* Everything is ok! */
        result = true;
      }
    }

    /* If incrementation of the iterator was successful, return true  */
    return result;
  }

  /**********************************************************************/
  /*! \brief Returns the current address being pointed to.
  *
  * Current address will be returned.
  *
  * \sa jumpTo()
  *
  * \retval   Current address being pointed to.
  ***********************************************************************/
  unsigned long currentAddress()
  {
    return ihIterator->first;
  }

  /**********************************************************************/
  /*! \brief Returns the lowest address currently available.
  *
  * Returns the first address that appears in the memory if there is data
  * present. If not, no value will be returned.
  *
  * \sa endAddress()
  *
  * \param address    - variable to hold address requested
  *
  * \retval true      - address existed and returned value is valid
  * \retval false     - address did not exist and returned valid is not
  *                     valid
  ***********************************************************************/
  bool startAddress(unsigned long * address)
  {
    if (ihContent.size() != 0)
    {
      map<unsigned long, unsigned char>::iterator it;

      it = ihContent.begin();
      *address = (*it).first;
      return true;
    }

    return false;
  }

  /**********************************************************************/
  /*! \brief Returns the highest address currently available.
  *
  * Returns the last address that appears in the memory if there is data
  * present. If not, no value will be returned.
  *
  * \param address    - variable to hold address requested
  *
  * \retval true      - address existed and returned value is valid
  * \retval false     - address did not exist and returned valid is not
  *                     valid
  *
  * \sa startAddress()
  ***********************************************************************/
  bool endAddress(unsigned long * address)
  {
    if (ihContent.size() != 0)
    {
      map<unsigned long, unsigned char>::reverse_iterator rit;

      rit = ihContent.rbegin();
      *address = (*rit).first;
      return true;
    }

    return false;
  }

  /**********************************************************************/
  /*! \brief Returns the data to which the iterator is currently pointing.
  *
  * Returns the data to which the internal iterator (pointer) is currently
  * pointing. If no data is in memory, this function returns false.
  *
  * \param data       - variable to hold data requested
  *
  * \retval true      - data was available and returned value is valid
  * \retval false     - data was not available and returned valid is not
  *                     valid
  *
  * \sa insertData(), overwriteData()
  ***********************************************************************/
  bool getData(unsigned char * data)
  {
    if (!ihContent.empty() && (ihIterator != ihContent.end()))
    {
      *data = ihIterator->second;
      return true;
    }
    return false;
  }

  /**********************************************************************/
  /*! \brief Returns the data from the desired address.
  *
  * Returns the data for the desired address. If the address has no data
  * assigned to it, the function returns false, the pointer to data is not
  * written and the class's address pointer remains unchanged. If the
  * address has data assigned to it, the pointer to data will be written
  * with the data found and the class's address pointer will be moved to
  * this new location.
  *
  * \param data       - variable to hold data requested
  * \param address    - address to be queried for valid data
  *
  * \retval true      - data was available and returned value is valid
  * \retval false     - data was not available and returned valid is not
  *                     valid
  *
  * \sa insertData(), overwriteData()
  ***********************************************************************/
  bool getData(unsigned char * data, unsigned long address)
  {
    bool found = false;
    map<unsigned long, unsigned char>::iterator localIterator;

    if (!ihContent.empty())
    {
      localIterator = ihContent.find(address);

      if (localIterator != ihContent.end())
      {
        found = true;
        ihIterator = localIterator;
        *data = ihIterator->second;
      }
    }

    return found;
  }

  /**********************************************************************/
  /*! \brief Inserts desired byte at the current address pointer.
  *
  * Inserts byte of data at the current address pointer
  *
  * \param data       - data byte to be inserted
  *
  * \retval true      - data insertion was successful
  * \retval false     - data insertion failed
  *
  * \sa getAddress(), overwriteData()
  ***********************************************************************/
  bool insertData(unsigned char data);

  /**********************************************************************/
  /*! \brief Inserts desired byte at the desired address.
  *
  * Inserts byte of data at the desired address.
  *
  * \param data       - data byte to be inserted
  * \param address    - address at which to insert data
  *
  * \retval true      - data insertion was successful
  * \retval false     - data insertion failed
  *
  * \sa getAddress(), overwriteData()
  ***********************************************************************/
  bool insertData(unsigned char data, unsigned long address);

  /**********************************************************************/
  /*! \brief Forces insertion of desired byte at the current address pointer.
  *
  * Forces insertion of byte of data at the current address pointer
  *
  * \param data       - data byte to be inserted
  *
  * \sa getAddress()
  ***********************************************************************/
  void overwriteData(unsigned char data);

  /**********************************************************************/
  /*! \brief Forces insertion of desired byte at the desired address.
  *
  * Forces insertion of byte of data at the desired address.
  *
  * \param data       - data byte to be inserted
  * \param address    - address at which to insert data
  *
  * \sa getAddress()
  ***********************************************************************/
  void overwriteData(unsigned char data, unsigned long address);

  bool blankFill(unsigned char data);

  bool blankFill(unsigned char * const data, unsigned long sizeOfData);

  void blankFill(unsigned char * const data, unsigned long sizeOfData,
                 unsigned long endAddress);

  bool blankFillRandom();

  void blankFillRandom(unsigned long endAddress);

  bool blankFillAddressLowByte();

  void blankFillAddressLowByte(unsigned long endAddress);

  /**********************************************************************/
  /*! \brief Returns number of unread warning messages.
  *
  * Number of unread warning messages will be returned.
  *
  * \sa popNextWarning(), getNoErrors(), popNextError()
  ***********************************************************************/
  unsigned long getNoWarnings()
  {
    return msgWarning.noOfWarnings;
  }

  /**********************************************************************/
  /*! \brief Returns number of unread error messages.
  *
  * Number of unread error messages will be returned.
  *
  * \sa popNextWarning(), getNoWarnings(), popNextError()
  ***********************************************************************/
  unsigned long getNoErrors()
  {
    return msgError.noOfErrors;
  }

  /**********************************************************************/
  /*! \brief Pop next warning message from the list of warnings.
  *
  * Next warning message is returned from the list of warnings. If there
  * are no more warning in the list, the string will be unchanged.
  *
  * \param    warning - variable to store warning string to be returned
  *
  * \retval   true    - more warning messages are available
  * \retval   false   - no more warning messages are available
  *
  * \sa getNoWarnings(), getNoErrors(), popNextError()
  ***********************************************************************/
  bool popNextWarning(string& warning)
  {
    if (msgWarning.noOfWarnings > 0)
    {
      warning = msgWarning.ihWarnings.front();

      msgWarning.ihWarnings.pop_front();

      msgWarning.noOfWarnings = msgWarning.ihWarnings.size();

      return true;
    }
    else
    {
      return false;
    }
  }

  /**********************************************************************/
  /*! \brief Pop next error message from the list of errors.
  *
  * Next error message is returned from the list of errors. If there are
  * no more errors in the list, no string will be returned unchanged.
  *
  * \param    error   - variable to store error string to be returned
  *
  * \retval   true    - more error messages are available
  * \retval   false   - no more error messages are available
  *
  * \sa getNoWarnings(), getNoErrors(), popNextError()
  ***********************************************************************/
  bool popNextError(string& error)
  {
    if (msgError.noOfErrors > 0)
    {
      error = msgError.ihErrors.front();

      msgError.ihErrors.pop_front();

      msgError.noOfErrors = msgError.ihErrors.size();

      return true;
    }
    else
    {
      return false;
    }
  }

  /**********************************************************************/
  /*! \brief Returns segment start address for the IP and ES registers.
  *
  * If these values exist, they will be returned. If not, the function
  * returns false.
  *
  * \param    ipRegister  - variable to store IP register's value
  * \param    csRegister  - variable to store CS register's value
  *
  * \retval   true    - IP and CS registers have defined values
  * \retval   false   - IP and CS registers do not contain values
  *
  * \sa getStartLinearAddress(), setStartSegmentAddress(),
  *     setStartLinearAddress()
  ***********************************************************************/
  bool getStartSegmentAddress(unsigned short * ipRegister,
                              unsigned short * csRegister)
  {
    if (startSegmentAddress.exists == true)
    {
      *ipRegister = startSegmentAddress.ipRegister;
      *csRegister = startSegmentAddress.csRegister;
    }

    return startSegmentAddress.exists;
  }

  /**********************************************************************/
  /*! \brief Returns segment linear address for the EIP register.
  *
  * If this value exists, they will be returned. If not, the function
  * returns false.
  *
  * \param    eipRegister - variable to store EIP register's value
  *
  * \retval   true    - EIP register has defined value
  * \retval   false   - EIP register do not contain value
  *
  * \sa getStartSegmentAddress(), setStartSegmentAddress(),
  *     setStartLinearAddress()
  ***********************************************************************/
  bool getStartLinearAddress(unsigned long * eipRegister)
  {
    if (startLinearAddress.exists == true)
    {
      *eipRegister = startLinearAddress.eipRegister;
    }

    return startLinearAddress.exists;
  }

  /**********************************************************************/
  /*! \brief Sets the segment start address for the IP and CS registers.
  *
  * Allows user to define or redefine the contents of the IP and CS
  * registers
  *
  * \param    ipRegister  - desired IP register value
  * \param    csRegister  - desired CS register value
  *
  * \sa getStartLinearAddress(), getStartSegmentAddress(),
  *     setStartLinearAddress()
  ***********************************************************************/
  void setStartSegmentAddress(unsigned short ipRegister,
                              unsigned short csRegister)
  {
    startSegmentAddress.ipRegister = ipRegister;
    startSegmentAddress.csRegister = csRegister;
    startSegmentAddress.exists = true;
  }

  /**********************************************************************/
  /*! \brief Sets the segment start address for the EIP register.
  *
  * Allows user to define or redefine the contents of the EIP register
  *
  * \param    eipRegister - desired EIP register value
  *
  * \sa getStartSegmentAddress(), setStartSegmentAddress(),
  *     getStartLinearAddress()
  ***********************************************************************/
  void setStartLinearAddress(unsigned long eipRegister)
  {
    startLinearAddress.eipRegister = eipRegister;
    startLinearAddress.exists = true;
  }

  /**********************************************************************/
  /*! \brief Turns on segment addressing mode during encoding.
  *
  * Uses the Segment Address Record during encoding.
  ***********************************************************************/
  void segmentAddressingOn()
  {
    segmentAddressMode = true;
  }

  /**********************************************************************/
  /*! \brief Turns on linear addressing mode during encoding.
  *
  * Uses the Linear Address Record during encoding.
  ***********************************************************************/
  void linearAddressingOn()
  {
    segmentAddressMode = false;
  }

  /**********************************************************************/
  /*! \brief Turns on textual output to cout during decoding.
  *
  * Per record single line output to cout during decoding of Intel HEX
  * files.
  ***********************************************************************/
  void verboseOn()
  {
    verbose = true;
  }

  /**********************************************************************/
  /*! \brief Turns off textual output to cout during decoding.
  *
  * No output to cout during decoding of Intel HEX files.
  ***********************************************************************/
  void verboseOff()
  {
    verbose = false;
  }
};
#endif
