Source file: /~heha/hs/gputils64-210929.zip/libgputils/gpreadhex.cpp

/* Read ".HEX" (Intel-Hex) files and store it in memory
   Copyright 2001-2005	Craig Franklin
*/

#include "stdhdr.h"
#include "libgputils.h"

				  // used in	INHX8	INHX16	INHX32
#define IHEX_RECTYPE_DATA		0//	yes	yes	yes
#define IHEX_RECTYPE_EOF		1//	yes	yes	yes
#define IHEX_RECTYPE_EXT_SEG_ADDR	2//	no	yes	no
#define IHEX_RECTYPE_START_SEG_ADDR	3//	no	yes	no
#define IHEX_RECTYPE_EXT_LIN_ADDR	4//	no	no	yes
#define IHEX_RECTYPE_START_LIN_ADDR	5//	no	no	yes
				// address bits	16	20	32

struct Hexdata:public hex_data{
  uint8_t checksum;
  FILE*   infile;
  char*   linept;
  char    linebuf[520];		// large structures at end -> shorter code
  uint8_t _readbyte();
  uint16_t _readword();
  Hexdata(const char*,MemBlock_t*);
};

/*------------------------------------------------------------------------------------------------*/

/* Converts a single ASCII character into a number. */

static uint8_t _a2n(uint8_t Character) {
  uint8_t number;

  if (Character <= '9') {
    number = Character - '0';
  }
  else {
    /* Convert lower case to upper. */
    Character &= ~('a' - 'A');
    number = Character - ('A' - 10);
  } 
  return number;
}

/*------------------------------------------------------------------------------------------------*/

uint8_t Hexdata::_readbyte() {
  uint8_t number;

  linept++;
  number  = (uint8_t)(_a2n((uint8_t)(*linept)) << 4);
  linept++;
  number |= _a2n((uint8_t)(*linept));

  checksum += number;
  return number;
} 

/*------------------------------------------------------------------------------------------------*/

uint16_t Hexdata::_readword() {
  uint16_t number;

  number  = (uint16_t)_readbyte();  
  number |= (uint16_t)_readbyte() << 8;
  return number; 
}

/*------------------------------------------------------------------------------------------------*/

static uint16_t _swapword(uint16_t Input) {
  uint16_t number;

  number = (uint16_t)((Input & 0xFF) << 8) | (uint16_t)((Input & 0xFF00) >> 8);
  return number;
}

/*------------------------------------------------------------------------------------------------*/
Hexdata::Hexdata(const char* File_name, MemBlock_t* M) {
  /* Open the input file. */
  infile = fopen(File_name, "rt");
  if (!infile) {
    perror(File_name);
    exit(1);
  }
    
  /* Go to the beginning of the file. */
  fseek(infile, 0L, SEEK_SET);

  /* Set the line pointer to the beginning of the line buffer. */
  unsigned page   = 0;

  /* Read a line of data from the file, if NULL stop. */
  while (fgets(linebuf, sizeof linebuf, infile)) {
    /* Set the line pointer to the beginning of the line buffer. */
    linept = linebuf;
    checksum = 0;
    /* Fetch the number of bytes. */
    unsigned length = _readbyte();
    if (!length) fclose(infile);

    /* Fetch the address. */
    unsigned address = _swapword(_readword());

    if (hex_format == INHX16) {
      address *= 2;
      length  *= 2;
    }

    /* Read the type of record. */
    unsigned type = _readbyte();

    if (type == IHEX_RECTYPE_EXT_LIN_ADDR) {
      if (hex_format == INHX16) {
        printf("\nHex Format Error\n");
        fclose(infile);
        error = true;
      }

      /* INHX32 segment line. */
      page = (unsigned)((_readbyte() << 8) + _readbyte()) << 16;
      hex_format = INHX32;
    }else{
      /* Read the data (skipping last byte if at odd address). */
      for (unsigned i = 0; i < length; ++i) {
	uint8_t byte = _readbyte();

	if (hex_format == INHX16) {
	  gp_mem_b_put(M, page | ((address + i) ^ 1), byte, File_name, NULL);
	}
	else {
	  gp_mem_b_put(M, page | (address + i),       byte, File_name, NULL);
	}
      }

      size += length;
    }

    /* Read the checksum, data is thrown away. */
    _readbyte();

    if (checksum) { 
      if (hex_format == INHX8M) {
        /*  First attempt at INHX8M failed, try INHX16. */
        fseek(infile, 0L, SEEK_SET);	  
        hex_format = INHX16;
        size       = 0;
        /* Data in i_memory is trash. */
        gp_mem_i_free(M);
        M = gp_mem_i_create();
      }else{
        printf("\nChecksum Error\n");
        fclose(infile);
        error = true;
      }
    }

    /* Set the line pointer to the beginning of the line buffer. */
    linept = linebuf;
  }
  fclose(infile);
}

FUNC(hex_data_t*) gp_readhex(const char* File_name, MemBlock_t* M) {
  return new Hexdata(File_name,M);
}
Detected encoding: UTF-80