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 *.d
src/fvhex2bin src/fvhex2bin
src/libfvhex2bin.a src/libfvhex2bin.a
/data/flangers.bin

19
src/Makefile

@ -1,32 +1,19 @@
TARGET_EXE=fvhex2bin TARGET_EXE=fvhex2bin
TARGET_LIB=lib$(TARGET_EXE).a 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+=-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_ALL=$(wildcard *.c)
SRC_EXE=$(TARGET_EXE).c SRC_EXE=$(TARGET_EXE).c
SRC_LIB=$(filter-out $(SRC_EXE), $(SRC_ALL)) SRC_LIB=$(filter-out $(SRC_EXE), $(SRC_ALL))
#OBJ_EXE=$(subst .c,.o,$(SRC_EXE))
OBJ_LIB=$(subst .c,.o,$(SRC_LIB)) OBJ_LIB=$(subst .c,.o,$(SRC_LIB))
DEPENDS=$(subst .c,.d,$(SRC_ALL)) DEPENDS=$(subst .c,.d,$(SRC_ALL))
ifneq ($(MAKECMDGOALS),clean) ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS) -include $(DEPENDS)
endif endif
.PHONY: all clean uninstall install .PHONY: all clean test
.DEFAULT_GOAL := all .DEFAULT_GOAL := all
all: $(TARGET_EXE) all: $(TARGET_EXE)
@ -39,6 +26,10 @@ $(TARGET_EXE): $(SRC_EXE) $(TARGET_LIB)
$(TARGET_LIB): $(OBJ_LIB) $(TARGET_LIB): $(OBJ_LIB)
$(AR) -cr $@ $^ $(AR) -cr $@ $^
test: all
./fvhex2bin -i ../data/flangers.hex -o ../data/flangers.bin
cmp -l ../data/flangers.bin ../data/flangers.hex.bin.target
clean: clean:
rm $(OBJ_LIB) $(TARGET_LIB) $(TARGET_EXE) $(DEPENDS) rm $(OBJ_LIB) $(TARGET_LIB) $(TARGET_EXE) $(DEPENDS)

133
src/fvhex2bin.c

@ -21,69 +21,33 @@
* Distribute freely, mark modified copies as such. * Distribute freely, mark modified copies as such.
*/ */
#include "kk_ihex_read.h" #include "libfvhex2bin.h"
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.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[]) int main(int argc, char *argv[])
{ {
struct ihex_state ihex; char *infile = NULL;
FILE *infile = stdin; char *outfile = NULL;
ihex_count_t count;
char buf[256];
outfile = stdout;
while (--argc) { while (--argc) {
char *arg = *(++argv); char *arg = *(++argv);
if (arg[0] == '-' && arg[1] && arg[2] == '\0') { if (arg[0] == '-' && arg[1] && arg[2] == '\0') {
switch (arg[1]) { 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': case 'i':
if (--argc == 0) { if (--argc == 0) {
goto invalid_argument; goto invalid_argument;
} }
++argv; ++argv;
if (!(infile = fopen(*argv, "r"))) { infile = *argv;
goto argument_error;
}
break; break;
case 'o': case 'o':
if (--argc == 0) { if (--argc == 0) {
goto invalid_argument; goto invalid_argument;
} }
++argv; ++argv;
if (!(outfile = fopen(*argv, "wb"))) { outfile = *argv;
goto argument_error;
}
break;
case 'v':
debug_enabled = 1;
break; break;
case 'h': case 'h':
case '?': case '?':
@ -97,98 +61,13 @@ int main(int argc, char *argv[])
invalid_argument: invalid_argument:
(void)fprintf(stderr, "Invalid argument: %s\n", arg); (void)fprintf(stderr, "Invalid argument: %s\n", arg);
usage: usage:
(void)fprintf(stderr, "kk_ihex " KK_IHEX_VERSION " - Copyright (c) 2013-2015 Kimmo Kulovesi\n");
(void)fprintf( (void)fprintf(
stderr, stderr,
"Usage: ihex2bin ([-a <address_offset>]|[-A])" "Usage: ihex2bin ([-a <address_offset>]|[-A])"
" [-o <out.bin>] [-i <in.hex>] [-v]\n"); " [-o <out.bin>] [-i <in.hex>] [-v]\n");
return arg ? EXIT_FAILURE : EXIT_SUCCESS; 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; 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 // To implement fully correct segmented addressing, compute the address
// of _each byte_ with its index in `data` as follows: // 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: #else // IHEX_DISABLE_SEGMENTS:

35
src/kk_ihex_read.c

@ -10,6 +10,14 @@
#include "kk_ihex_read.h" #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 IHEX_START ':'
#define ADDRESS_HIGH_MASK ((ihex_address_t)0xFFFF0000U) #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_MASK 0x78
#define IHEX_READ_STATE_OFFSET 3 #define IHEX_READ_STATE_OFFSET 3
void void ihex_begin_read(struct ihex_state *const ihex)
ihex_begin_read (struct ihex_state * const ihex) { {
ihex->address = 0; ihex->address = 0;
#ifndef IHEX_DISABLE_SEGMENTS #ifndef IHEX_DISABLE_SEGMENTS
ihex->segment = 0; ihex->segment = 0;
@ -43,22 +51,22 @@ ihex_begin_read (struct ihex_state * const ihex) {
ihex->length = 0; ihex->length = 0;
} }
void void ihex_read_at_address(struct ihex_state *const ihex, ihex_address_t address)
ihex_read_at_address (struct ihex_state * const ihex, ihex_address_t address) { {
ihex_begin_read(ihex); ihex_begin_read(ihex);
ihex->address = address; ihex->address = address;
} }
#ifndef IHEX_DISABLE_SEGMENTS #ifndef IHEX_DISABLE_SEGMENTS
void void ihex_read_at_segment(struct ihex_state *const ihex, ihex_segment_t segment)
ihex_read_at_segment (struct ihex_state * const ihex, ihex_segment_t segment) { {
ihex_begin_read(ihex); ihex_begin_read(ihex);
ihex->segment = segment; ihex->segment = segment;
} }
#endif #endif
void void ihex_end_read(struct ihex_state *const ihex)
ihex_end_read (struct ihex_state * const ihex) { {
uint_fast8_t type = ihex->flags & IHEX_READ_RECORD_TYPE_MASK; uint_fast8_t type = ihex->flags & IHEX_READ_RECORD_TYPE_MASK;
uint_fast8_t sum; uint_fast8_t sum;
if ((sum = ihex->length) == 0 && type == IHEX_DATA_RECORD) { if ((sum = ihex->length) == 0 && type == IHEX_DATA_RECORD) {
@ -89,8 +97,8 @@ ihex_end_read (struct ihex_state * const ihex) {
ihex->flags = 0; ihex->flags = 0;
} }
void void ihex_read_byte(struct ihex_state *const ihex, const char byte)
ihex_read_byte (struct ihex_state * const ihex, const char byte) { {
uint_fast8_t b = (uint_fast8_t)byte; uint_fast8_t b = (uint_fast8_t)byte;
uint_fast8_t len = ihex->length; uint_fast8_t len = ihex->length;
uint_fast8_t state = (ihex->flags & IHEX_READ_STATE_MASK); uint_fast8_t state = (ihex->flags & IHEX_READ_STATE_MASK);
@ -169,13 +177,10 @@ save_read_state:
ihex->flags |= state << IHEX_READ_STATE_OFFSET; ihex->flags |= state << IHEX_READ_STATE_OFFSET;
} }
void void ihex_read_bytes(struct ihex_state *restrict ihex, const char *restrict data, ihex_count_t count)
ihex_read_bytes (struct ihex_state * restrict ihex, {
const char * restrict data,
ihex_count_t count) {
while (count > 0) { while (count > 0) {
ihex_read_byte(ihex, *data++); ihex_read_byte(ihex, *data++);
--count; --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); // 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 // 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 // are not specified in the input data and they are non-zero
void ihex_read_at_address(struct ihex_state *ihex, void ihex_read_at_address(struct ihex_state *ihex, ihex_address_t address);
ihex_address_t address);
// Read a single character // Read a single character
void ihex_read_byte(struct ihex_state *ihex, char chr); void ihex_read_byte(struct ihex_state *ihex, char chr);
// Read `count` bytes from `data` // Read `count` bytes from `data`
void ihex_read_bytes(struct ihex_state * restrict ihex, void ihex_read_bytes(struct ihex_state *restrict ihex, const char *restrict data, ihex_count_t count);
const char * restrict data,
ihex_count_t count);
// End reading (may call `ihex_data_read` if there is data waiting) // End reading (may call `ihex_data_read` if there is data waiting)
void ihex_end_read(struct ihex_state *ihex); void ihex_end_read(struct ihex_state *ihex);
@ -100,7 +97,8 @@ void ihex_end_read(struct ihex_state *ihex);
// return !error; // 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_record_type_t type,
ihex_bool_t checksum_mismatch); 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