Last modified 2013-10-10 23:01:51 PDT

libGIS - Atmel Generic, Intel HEX, and Motorola S-Record Parser Routines

Git: git clone git://


Latest source: libgis-master zip

Please feel free to report any issues at github or by email at vsergeev at gmail.



libGIS is a collection of utility functions to create, read, and write Atmel Generic, Intel HEX8, and Motorola S-Record formatted files. libGIS is typically not compiled into a library, since the file formats it supports are so specific, and the source code for each file format is contained in only two files.

I wrote libGIS was because I wanted a clean, flexible, and easy-to-use set of functions to deal with the nasty parsing of these formatted binary files. libGIS supports Intel HEX8 and Motorola S-Record formatted files, which are undoubtedly the most popular in use with embedded systems. libGIS also supports the Atmel Generic binary format, which may be applicable in projects targetting the Atmel AVR.

libGIS is very convenient for disassembler, assembler, binary file converter, and other related projects. It is written in C (tested with gcc), but can also be compiled with a C++ compiler (such as g++), which means it can be implemented in any C/C++ projects requiring parsing of such formatted files. libGIS uses the standard C library in its backend.

libGIS is clean and tiny. Each file format is supported with two files, one is the C source code and the other is the C header file, which makes compiling whichever format you need to support very easy. The interface to the utility functions is very straight forward, as demonstrated by the included testGIS.c program.

The code of each file format parser has a structure to store record information, and 4-5 basic functions to create, read, write, print, and checksum (for Intel HEX8 and Motorola S-Record) records. The error handling in libGIS will never leave you out of the dark, as the possible error codes and what they mean are clearly defined in the header file of the format parser you’re using.

libGIS is a low-level interface to formatted binary files, and it will not automatically generate, for example, extended addresses in the Intel HEX8 format, or the header record in the S-Record format. libGIS helps in the actual writing and reading of the raw records, not dealing with the content going into them (but still adhering to the record and field size specifications).

libGIS is offered with two licensing options. The first is Public Domain, which is free for any kind of use (personal or commercial), without warranty of any kind, and no requirement for attribution. The second is MIT/X11.

The following function prototypes summarize the interface of libGIS:

Atmel Generic format:
int New_AtmelGenericRecord(uint32_t address, uint16_t data, AtmelGenericRecord *genericRecord);
int Read_AtmelGenericRecord(AtmelGenericRecord *genericRecord, FILE *in);
int Write_AtmelGenericRecord(const AtmelGenericRecord *genericRecord, FILE *out);
void Print_AtmelGenericRecord(const AtmelGenericRecord *genericRecord);

Intel HEX8 format:
int New_IHexRecord(int type, uint16_t address, const uint8_t *data, int dataLen, IHexRecord *ihexRecord);
int Read_IHexRecord(IHexRecord *ihexRecord, FILE *in);
int Write_IHexRecord(const IHexRecord *ihexRecord, FILE *out);
void Print_IHexRecord(const IHexRecord *ihexRecord);
uint8_t Checksum_IHexRecord(const IHexRecord *ihexRecord);

Motorola S-Record format:
int New_SRecord(int type, uint32_t address, const uint8_t *data, int dataLen, SRecord *srec);
int Read_SRecord(SRecord *srec, FILE *in);
int Write_SRecord(const SRecord *srec, FILE *out);
void Print_SRecord(const SRecord *srec);
uint8_t Checksum_SRecord(const SRecord *srec);

This package includes the parsing for the following formats:

Atmel Generic format: atmel_generic.c and atmel_generic.h

Intel HEX8 format: ihex.c and ihex.h

Motorola S-Record format: srecord.c and srecord.h

Also included is a test program (testGIS.c, with a Makefile to compile it) that prints all of the records contained in a Atmel Generic, Intel HEX8 or Motorola S-Record formatted file, documentation in PDF and html formats, and the README containing all of this.

Please email me (vsergeev at gmail dot com) any bugs, problems, or suggestions you encounter with using libGIS, they are highly appreciated.

Sample program - sizeGIS.c

sizeGIS: Counts the total number of data bytes stored in an Atmel Generic, Intel HEX8, or Motorola S-Record formatted file — useful for finding out exactly how much memory the formatted file will use when it is flashed/transferred/downloaded/etc.

 * sizeGIS.c
 * Compile with gcc -Wall atmel_generic.c ihex.c srecord.c sizeGIS.c -o sizeGIS
 * Very straight forward program that makes use of atmel_generic.h, ihex.h, and srecord.h.
 * This program counts the total number of data bytes stored in an Atmel Generic, 
 * Intel HEX8, or Motorola S-Record formatted file--useful for finding out exactly how
 * much memory the formatted file will use when it is flashed/transferred/downloaded/etc.
 * Author: Vanya A. Sergeev <>
 * Public Domain
#include <stdio.h>
#include <string.h>
#include "srecord.h"
#include "atmel_generic.h"
#include "ihex.h"

/* Windows doesn't have 'strcasecmp' but does have stricmp */
#ifdef _WIN32
        #define strcasecmp stricmp

int main (int argc, const char * argv[]) {
	FILE *fp;
	AtmelGenericRecord arec;
	IHexRecord irec;
	SRecord srec;
	int recordCount = 0, dataByteSum = 0;

	if (argc < 3) {
		fprintf(stderr, "Usage: %s <file format> <file>\n", argv[0]);
 		fprintf(stderr, "This program counts the total number of data bytes stored in an Atmel Generic, "); 
 		fprintf(stderr, "Intel HEX8, or Motorola S-Record formatted file--useful for finding out exactly how ");
 	 	fprintf(stderr, "much memory the formatted file will use when it is flashed/transferred/downloaded/etc.\n\n");
		fprintf(stderr, "<file format> can be generic, ihex, or srecord.\n");
		fprintf(stderr, "<file> is the path to the file containing the records.\n");
		return -1;
	fp = fopen(argv[2], "r");
	if (fp == NULL) {
		perror("Error opening file!");
		return -1;
	if (strcasecmp(argv[1], "generic") == 0) {
		while (Read_AtmelGenericRecord(&arec, fp) == ATMEL_GENERIC_OK) {
			dataByteSum += 2; /* Data field in every Atmel Generic record is a word (2 bytes) */
	} else if (strcasecmp(argv[1], "ihex") == 0) {
		while (Read_IHexRecord(&irec, fp) == IHEX_OK) {
			/* Only count data records */
			if (irec.type == IHEX_TYPE_00) { 
				dataByteSum += irec.dataLen;

	} else if (strcasecmp(argv[1], "srecord") == 0) {
		while (Read_SRecord(&srec, fp) == SRECORD_OK) {
			/* Only count data records */
			if (srec.type == SRECORD_TYPE_S1 || srec.type == SRECORD_TYPE_S2 || srec.type == SRECORD_TYPE_S3) { 
				dataByteSum += srec.dataLen;
	} else {
		fprintf(stderr, "Invalid file format specified!\n");
		return -1;
	printf("Number of data records: %d\n", recordCount);
	printf("Number of data bytes: %d\n", dataByteSum);
	return 0;


comments powered by Disqus