Browse Source

Supermogrify the thing into a lib

master
heck 2 years ago
parent
commit
e57077a3d1
  1. 1
      .gitignore
  2. 19
      src/Makefile
  3. 133
      src/fvhex2bin.c
  4. 3
      src/kk_ihex.h
  5. 35
      src/kk_ihex_read.c
  6. 10
      src/kk_ihex_read.h
  7. 140
      src/libfvhex2bin.c
  8. 3
      src/libfvhex2bin.h

1
.gitignore

@ -2,3 +2,4 @@
*.d
src/fvhex2bin
src/libfvhex2bin.a
/data/flangers.bin

19
src/Makefile

@ -1,32 +1,19 @@
TARGET_EXE=fvhex2bin
TARGET_LIB=lib$(TARGET_EXE).a
# default config
#SYS_PREFIX?=/opt/local
# System
#SYS_INC_PATH?=$(SYS_PREFIX)/include
#SYS_LIB_PATH?=$(SYS_PREFIX)/lib
CFLAGS+=-std=c99 -MMD -MP -Wno-format-extra-args -Wno-deprecated-declarations -fvisibility=hidden
#CFLAGS+=-isystem$(SYS_INC_PATH)
#LDFLAGS+=-DMACOSX_DEPLOYMENT_TARGET=11.00 -framework Foundation -framework IOKit -framework Security
#STATIC_LINK_LIBS=$(SYS_LIB_PATH)/libusb-1.0.a
SRC_ALL=$(wildcard *.c)
SRC_EXE=$(TARGET_EXE).c
SRC_LIB=$(filter-out $(SRC_EXE), $(SRC_ALL))
#OBJ_EXE=$(subst .c,.o,$(SRC_EXE))
OBJ_LIB=$(subst .c,.o,$(SRC_LIB))
DEPENDS=$(subst .c,.d,$(SRC_ALL))
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS)
endif
.PHONY: all clean uninstall install
.PHONY: all clean test
.DEFAULT_GOAL := all
all: $(TARGET_EXE)
@ -39,6 +26,10 @@ $(TARGET_EXE): $(SRC_EXE) $(TARGET_LIB)
$(TARGET_LIB): $(OBJ_LIB)
$(AR) -cr $@ $^
test: all
./fvhex2bin -i ../data/flangers.hex -o ../data/flangers.bin
cmp -l ../data/flangers.bin ../data/flangers.hex.bin.target
clean:
rm $(OBJ_LIB) $(TARGET_LIB) $(TARGET_EXE) $(DEPENDS)

133
src/fvhex2bin.c

@ -21,69 +21,33 @@
* Distribute freely, mark modified copies as such.
*/
#include "kk_ihex_read.h"
#include <stdbool.h>
#include "libfvhex2bin.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define AUTODETECT_ADDRESS (~0UL)
static FILE *outfile;
static unsigned long line_number = 1L;
static unsigned long file_position = 0L;
static unsigned long address_offset = 0UL;
static bool debug_enabled = 0;
int main(int argc, char *argv[])
{
struct ihex_state ihex;
FILE *infile = stdin;
ihex_count_t count;
char buf[256];
outfile = stdout;
char *infile = NULL;
char *outfile = NULL;
while (--argc) {
char *arg = *(++argv);
if (arg[0] == '-' && arg[1] && arg[2] == '\0') {
switch (arg[1]) {
case 'a':
if (--argc == 0) {
goto invalid_argument;
}
++argv;
errno = 0;
address_offset = strtoul(*argv, &arg, 0);
if (errno || arg == *argv) {
errno = errno ? errno : EINVAL;
goto argument_error;
}
break;
case 'A':
address_offset = AUTODETECT_ADDRESS;
break;
case 'i':
if (--argc == 0) {
goto invalid_argument;
}
++argv;
if (!(infile = fopen(*argv, "r"))) {
goto argument_error;
}
infile = *argv;
break;
case 'o':
if (--argc == 0) {
goto invalid_argument;
}
++argv;
if (!(outfile = fopen(*argv, "wb"))) {
goto argument_error;
}
break;
case 'v':
debug_enabled = 1;
outfile = *argv;
break;
case 'h':
case '?':
@ -97,98 +61,13 @@ int main(int argc, char *argv[])
invalid_argument:
(void)fprintf(stderr, "Invalid argument: %s\n", arg);
usage:
(void)fprintf(stderr, "kk_ihex " KK_IHEX_VERSION " - Copyright (c) 2013-2015 Kimmo Kulovesi\n");
(void)fprintf(
stderr,
"Usage: ihex2bin ([-a <address_offset>]|[-A])"
" [-o <out.bin>] [-i <in.hex>] [-v]\n");
return arg ? EXIT_FAILURE : EXIT_SUCCESS;
argument_error:
perror(*argv);
return EXIT_FAILURE;
}
ihex_read_at_address(
&ihex,
(address_offset != AUTODETECT_ADDRESS) ? (ihex_address_t)address_offset : 0);
while (fgets(buf, sizeof(buf), infile)) {
count = (ihex_count_t)strlen(buf);
ihex_read_bytes(&ihex, buf, count);
line_number += (count && buf[count - 1] == '\n');
}
ihex_end_read(&ihex);
if (infile != stdin) {
(void)fclose(infile);
}
hex2bin(infile, outfile);
return EXIT_SUCCESS;
}
ihex_bool_t ihex_data_read(struct ihex_state *ihex, ihex_record_type_t type, ihex_bool_t error)
{
if (error) {
(void)fprintf(stderr, "Checksum error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if ((error = (ihex->length < ihex->line_length))) {
(void)fprintf(stderr, "Line length error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if (!outfile) {
(void)fprintf(stderr, "Excess data after end of file record\n");
exit(EXIT_FAILURE);
}
if (type == IHEX_DATA_RECORD) {
unsigned long address = (unsigned long)IHEX_LINEAR_ADDRESS(ihex);
if (address < address_offset) {
if (address_offset == AUTODETECT_ADDRESS) {
// autodetect initial address
address_offset = address;
if (debug_enabled) {
(void)fprintf(stderr, "Address offset: 0x%lx\n", address_offset);
}
} else {
(void)fprintf(stderr, "Address underflow on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
}
address -= address_offset;
if (address != file_position) {
if (debug_enabled) {
(void)fprintf(
stderr,
"Seeking from 0x%lx to 0x%lx on line %lu\n",
file_position,
address,
line_number);
}
if (outfile == stdout || fseek(outfile, (long)address, SEEK_SET)) {
if (file_position < address) {
// "seek" forward in stdout by writing NUL bytes
do {
(void)fputc('\0', outfile);
} while (++file_position < address);
} else {
perror("fseek");
exit(EXIT_FAILURE);
}
}
file_position = address;
}
if (!fwrite(ihex->data, ihex->length, 1, outfile)) {
perror("fwrite");
exit(EXIT_FAILURE);
}
file_position += ihex->length;
} else if (type == IHEX_END_OF_FILE_RECORD) {
if (debug_enabled) {
(void)fprintf(stderr, "%lu bytes written\n", file_position);
}
if (outfile != stdout) {
(void)fclose(outfile);
}
outfile = NULL;
}
return true;
}

3
src/kk_ihex.h

@ -172,7 +172,8 @@ typedef uint8_t ihex_record_type_t;
// To implement fully correct segmented addressing, compute the address
// of _each byte_ with its index in `data` as follows:
//
#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((((ihex)->address + (byte_index)) & 0xFFFFU) + (((ihex_address_t)((ihex)->segment)) << 4))
#define IHEX_BYTE_ADDRESS(ihex, byte_index) \
((((ihex)->address + (byte_index)) & 0xFFFFU) + (((ihex_address_t)((ihex)->segment)) << 4))
#else // IHEX_DISABLE_SEGMENTS:

35
src/kk_ihex_read.c

@ -10,6 +10,14 @@
#include "kk_ihex_read.h"
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#define IHEX_START ':'
#define ADDRESS_HIGH_MASK ((ihex_address_t)0xFFFF0000U)
@ -32,8 +40,8 @@ enum ihex_read_state {
#define IHEX_READ_STATE_MASK 0x78
#define IHEX_READ_STATE_OFFSET 3
void
ihex_begin_read (struct ihex_state * const ihex) {
void ihex_begin_read(struct ihex_state *const ihex)
{
ihex->address = 0;
#ifndef IHEX_DISABLE_SEGMENTS
ihex->segment = 0;
@ -43,22 +51,22 @@ ihex_begin_read (struct ihex_state * const ihex) {
ihex->length = 0;
}
void
ihex_read_at_address (struct ihex_state * const ihex, ihex_address_t address) {
void ihex_read_at_address(struct ihex_state *const ihex, ihex_address_t address)
{
ihex_begin_read(ihex);
ihex->address = address;
}
#ifndef IHEX_DISABLE_SEGMENTS
void
ihex_read_at_segment (struct ihex_state * const ihex, ihex_segment_t segment) {
void ihex_read_at_segment(struct ihex_state *const ihex, ihex_segment_t segment)
{
ihex_begin_read(ihex);
ihex->segment = segment;
}
#endif
void
ihex_end_read (struct ihex_state * const ihex) {
void ihex_end_read(struct ihex_state *const ihex)
{
uint_fast8_t type = ihex->flags & IHEX_READ_RECORD_TYPE_MASK;
uint_fast8_t sum;
if ((sum = ihex->length) == 0 && type == IHEX_DATA_RECORD) {
@ -89,8 +97,8 @@ ihex_end_read (struct ihex_state * const ihex) {
ihex->flags = 0;
}
void
ihex_read_byte (struct ihex_state * const ihex, const char byte) {
void ihex_read_byte(struct ihex_state *const ihex, const char byte)
{
uint_fast8_t b = (uint_fast8_t)byte;
uint_fast8_t len = ihex->length;
uint_fast8_t state = (ihex->flags & IHEX_READ_STATE_MASK);
@ -169,13 +177,10 @@ save_read_state:
ihex->flags |= state << IHEX_READ_STATE_OFFSET;
}
void
ihex_read_bytes (struct ihex_state * restrict ihex,
const char * restrict data,
ihex_count_t count) {
void ihex_read_bytes(struct ihex_state *restrict ihex, const char *restrict data, ihex_count_t count)
{
while (count > 0) {
ihex_read_byte(ihex, *data++);
--count;
}
}

10
src/kk_ihex_read.h

@ -54,16 +54,13 @@ void ihex_begin_read(struct ihex_state *ihex);
// Begin reading at `address` (the lowest 16 bits of which will be ignored);
// this is required only if the high bytes of the 32-bit starting address
// are not specified in the input data and they are non-zero
void ihex_read_at_address(struct ihex_state *ihex,
ihex_address_t address);
void ihex_read_at_address(struct ihex_state *ihex, ihex_address_t address);
// Read a single character
void ihex_read_byte(struct ihex_state *ihex, char chr);
// Read `count` bytes from `data`
void ihex_read_bytes(struct ihex_state * restrict ihex,
const char * restrict data,
ihex_count_t count);
void ihex_read_bytes(struct ihex_state *restrict ihex, const char *restrict data, ihex_count_t count);
// End reading (may call `ihex_data_read` if there is data waiting)
void ihex_end_read(struct ihex_state *ihex);
@ -100,7 +97,8 @@ void ihex_end_read(struct ihex_state *ihex);
// return !error;
// }
//
extern ihex_bool_t ihex_data_read(struct ihex_state *ihex,
extern ihex_bool_t ihex_data_read(
struct ihex_state *ihex,
ihex_record_type_t type,
ihex_bool_t checksum_mismatch);

140
src/libfvhex2bin.c

@ -0,0 +1,140 @@
/*
* ihex2bin.c: Read Intel HEX format, write binary data.
*
* By default reads from stdin and writes to stdout. The command-line
* options `-i` and `-o` can be used to specify the input and output
* file, respectively. Specifying an output file allows sparse writes.
*
* NOTE: Many Intel HEX files produced by compilers/etc have data
* beginning at an address greater than zero, potentially causing very
* unnecessarily large files to be created. The command-line option
* `-a` can be used to specify the start address of the output file,
* i.e., the value will be subtracted from the IHEX addresses (the
* result must not be negative).
*
* Alternatively, the command-line option `-A` sets the address offset
* to the first address that would be written (i.e., first byte of
* data written will be at address 0).
*
* Copyright (c) 2013-2019 Kimmo Kulovesi, https://arkku.com
* Provided with absolutely no warranty, use at your own risk only.
* Distribute freely, mark modified copies as such.
*/
#include "kk_ihex_read.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define AUTODETECT_ADDRESS (~0UL)
static unsigned long line_number = 1L;
static unsigned long file_position = 0L;
static unsigned long address_offset = 0UL;
static bool debug_enabled = 0;
static FILE *infile = NULL;
static FILE *outfile = NULL;
int hex2bin(const char *infilename, const char *outfilename)
{
int ret = 0;
if (!(infile = fopen(infilename, "r"))) {
return 255;
}
if (!(outfile = fopen(outfilename, "wb"))) {
return 255;
}
struct ihex_state ihex;
ihex_count_t count;
char buf[256];
ihex_read_at_address(
&ihex,
(address_offset != AUTODETECT_ADDRESS) ? (ihex_address_t)address_offset : 0);
while (fgets(buf, sizeof(buf), infile)) {
count = (ihex_count_t)strlen(buf);
ihex_read_bytes(&ihex, buf, count);
line_number += (count && buf[count - 1] == '\n');
}
ihex_end_read(&ihex);
if (infile != stdin) {
(void)fclose(infile);
}
return ret;
}
ihex_bool_t ihex_data_read(struct ihex_state *ihex, ihex_record_type_t type, ihex_bool_t error)
{
if (error) {
(void)fprintf(stderr, "Checksum error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if ((error = (ihex->length < ihex->line_length))) {
(void)fprintf(stderr, "Line length error on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
if (!outfile) {
(void)fprintf(stderr, "Excess data after end of file record\n");
exit(EXIT_FAILURE);
}
if (type == IHEX_DATA_RECORD) {
unsigned long address = (unsigned long)IHEX_LINEAR_ADDRESS(ihex);
if (address < address_offset) {
if (address_offset == AUTODETECT_ADDRESS) {
// autodetect initial address
address_offset = address;
if (debug_enabled) {
(void)fprintf(stderr, "Address offset: 0x%lx\n", address_offset);
}
} else {
(void)fprintf(stderr, "Address underflow on line %lu\n", line_number);
exit(EXIT_FAILURE);
}
}
address -= address_offset;
if (address != file_position) {
if (debug_enabled) {
(void)fprintf(
stderr,
"Seeking from 0x%lx to 0x%lx on line %lu\n",
file_position,
address,
line_number);
}
if (outfile == stdout || fseek(outfile, (long)address, SEEK_SET)) {
if (file_position < address) {
// "seek" forward in stdout by writing NUL bytes
do {
(void)fputc('\0', outfile);
} while (++file_position < address);
} else {
perror("fseek");
exit(EXIT_FAILURE);
}
}
file_position = address;
}
if (!fwrite(ihex->data, ihex->length, 1, outfile)) {
perror("fwrite");
exit(EXIT_FAILURE);
}
file_position += ihex->length;
} else if (type == IHEX_END_OF_FILE_RECORD) {
if (debug_enabled) {
(void)fprintf(stderr, "%lu bytes written\n", file_position);
}
if (outfile != stdout) {
(void)fclose(outfile);
}
outfile = NULL;
}
return true;
}

3
src/libfvhex2bin.h

@ -0,0 +1,3 @@
#pragma once
int hex2bin(const char *infilename, const char *outfile);
Loading…
Cancel
Save