Skip to content
Snippets Groups Projects

Relax the requirements on the input format

4 files
+ 274
112
Compare changes
  • Side-by-side
  • Inline

Files

+ 245
95
@@ -913,136 +913,292 @@ int read_cmp_info(const char *file_name, struct cmp_info *info, int verbose_en)
@@ -913,136 +913,292 @@ int read_cmp_info(const char *file_name, struct cmp_info *info, int verbose_en)
/**
/**
* @brief reads n_word words of a hex-encoded data (or model) file to a uint8_t
* @brief skip a sequence of spaces (as identified by calling isspace)
* buffer
*
*
* @note data must be encoded as 2 hex digits separated by a white space or new
* @param str pointer to the null-terminated byte string to be interpreted
* line character e.g. "AB CD 12\n34 AB 12\n"
*
*
* @param file_name data/model file name
* @returns a pointer to the character after the spaces
* @param buf buffer to write the file content (can be NULL)
*/
 
 
static const char *skip_space(const char *str)
 
{
 
while (isspace(*str))
 
str++;
 
return str;
 
}
 
 
 
/**
 
* @brief skip a comment starting with '#' symbol ending with '\n' or '\0'
 
*
 
* @param str pointer to the null-terminated byte string to be interpreted
 
*
 
* @returns a pointer to the character after the comment
 
*/
 
 
static const char *skip_comment(const char *str)
 
{
 
char c = *str;
 
if (c == '#') {
 
do {
 
str++;
 
c = *str;
 
} while (c != '\0' && c != '\n');
 
if (c != '\0')
 
str++;
 
}
 
return str;
 
}
 
 
 
/**
 
* @brief Interprets an hex-encoded 8 bit integer value in a byte string pointed
 
* to by str.
 
* @details Discards any whitespace characters (as identified by calling isspace)
 
* until the first non-whitespace character is found, then takes maximum 2
 
* characters (with base 16) unsigned integer number representation and
 
* converts them to an uint8_t value. The function set the pointer
 
* pointed to by str_end to point to the character past the last character
 
* interpreted. If str_end is a null pointer, it is ignored.
 
*
 
* @param str pointer to the null-terminated byte string to be interpreted
 
* @param str_end pointer to a pointer to character (can be NULL)
 
*
 
* @returns Integer value corresponding to the contents of str on success. If no
 
* conversion can be performed, 0 is returned (errno is set to EINVAL)).
 
*/
 
 
static uint8_t str_to_uint8(const char *str, char **str_end)
 
{
 
const int BASE = 16;
 
int i;
 
uint8_t res = 0;
 
const char *orig;
 
 
str = skip_space(str);
 
 
orig = str;
 
 
for (i = 0; i < 2; i++) {
 
unsigned char c = *str;
 
 
if (c >= 'a')
 
c = c - 'a' + 10;
 
else if (c >= 'A')
 
c = c - 'A' + 10;
 
else if (c <= '9')
 
c = c - '0';
 
else
 
c = 0xff;
 
 
if (c >= BASE)
 
break;
 
 
res = res * BASE + c;
 
 
str++;
 
}
 
 
if (str_end)
 
*str_end = (char *)str;
 
 
if (str == orig) { /* no value read in */
 
errno = EINVAL;
 
res = 0;
 
}
 
 
return res;
 
}
 
 
 
/**
 
* @brief reads n_word words of a hex-encoded string to a uint8_t buffer
 
*
 
* @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage
 
* return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a
 
* sequence are used as separators. If a string contains more than three hexadecimal
 
* numeric characters (0123456789abcdefABCDEF) in a row without separators, a
 
* separator is added after every second hexadecimal numeric character.
 
* Comments after a '#' symbol until the end of the line are ignored.
 
* E.g. "# comment\n ABCD 1 2\n34B 12\n" are interpreted as {0xAB, 0xCD,
 
* 0x01, 0x02, 0x34, 0x0B, 0x12}.
 
*
 
* @param str pointer to the null-terminated byte string to be interpreted
 
* @param data buffer to write the interpreted content (can be NULL)
* @param n_word number of uint8_t data words to read in
* @param n_word number of uint8_t data words to read in
 
* @param file_name file name for better error output (can be NULL)
* @param verbose_en print verbose output if not zero
* @param verbose_en print verbose output if not zero
*
*
* @returns read data words; if buf == NULL the size in bytes to store the file
* @returns the size in bytes to store the string content; negative on error
* content; negative on error
*/
*/
ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int verbose_en)
static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word,
 
const char *file_name, int verbose_en)
{
{
/* This is a rather slow implementation. Performance can be improved by
const char *nptr = str;
* reading larger chunks */
char *eptr = NULL;
ssize_t n;
size_t i = 0;
FILE *fp;
char tmp_str[4]; /* 4 = 2 hex digit's + 1 white space + 1 \0 */
if (!file_name)
errno = 0;
return -1;
fp = fopen(file_name, "r");
if (!data)
if (fp == NULL) {
n_word =~0;
fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name,
strerror(errno));
return -1;
}
/* if buf is NULL we count the words in the file */
if (!file_name)
if (!buf)
file_name = "unknown file name";
n_word = ~0U;
for (n = 0; n < n_word; ) {
int j;
unsigned long read_val;
char *end;
/* read 3 characters */
if (!fgets(tmp_str, sizeof(tmp_str), fp)) {
if (ferror(fp)) {
fprintf(stderr, "%s: %s: Error: File error indicator set.\n",
PROGRAM_NAME, file_name);
goto error;
}
if (!buf) /* finished counting the sample */
for (i=0; i < n_word; ) {
 
uint8_t read_val;
 
unsigned char c = *nptr;
 
if (c == '\0') {
 
if (!data) /* finished counting the sample */
break;
break;
fprintf(stderr, "%s: %s: Error: The files do not contain enough data as requested.\n",
fprintf(stderr, "%s: %s: Error: The files do not contain enough data as requested.\n",
PROGRAM_NAME, file_name);
PROGRAM_NAME, file_name);
goto error;
return -1;
}
}
/* skip empty lines */
if (isspace(c)) {
if (tmp_str[0] == '\n')
nptr = skip_space(nptr);
continue;
continue;
}
/* skip comment lines */
if (c == '#') {
if (tmp_str[0] == '#') {
nptr = skip_comment(nptr);
int c;
do {
c = fgetc(fp);
} while (c != '\n' && c != EOF);
continue;
continue;
}
}
/* check the string formation */
read_val = str_to_uint8(nptr, &eptr);
for (j = 0; j < 2; j++) {
if (eptr < nptr) /* end pointer must be bigger or equal than the start pointer */
if (!isxdigit(tmp_str[j])) {
abort();
fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected format is like: 12 AB 23 CD .. ..\n",
c = *eptr;
PROGRAM_NAME, file_name);
if (c != '\0' && !isxdigit(c) && !isspace(c) && c != '#') {
goto error;
fprintf(stderr, "%s: %s: Error read in '%.*s'. The data are not correct formatted.\n",
}
PROGRAM_NAME, file_name, (int)(eptr-nptr+1), nptr);
 
return -1;
}
}
if (!isspace(tmp_str[2])) {
if (errno == EINVAL) {
fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected format is like: 12 AB 23 CD .. ..\n",
fprintf(stderr, "%s: %s: Error converting the data to integers.\n",
PROGRAM_NAME, file_name);
PROGRAM_NAME, file_name);
goto error;
return -1;
}
}
if (data) {
/* convert data to integer and write it into the buffer */
data[i] = read_val;
if (buf) {
if (verbose_en) { /* print data read in */
read_val = strtoul(tmp_str, &end, 16);
if (i == 0)
if (tmp_str == end || read_val > UINT8_MAX) {
fprintf(stderr, "%s: %s: Error: The data can not be converted to integer.\n",
PROGRAM_NAME, file_name);
goto error;
}
buf[n] = (uint8_t)read_val;
/* print data read in */;
if (verbose_en) {
if (n == 0)
printf("\n\n");
printf("\n\n");
printf("%02X", buf[n]);
printf("%02X", data[i]);
if (n && !((n + 1) % 32))
if (i && !((i + 1) % 32))
printf("\n");
printf("\n");
else
else
printf(" ");
printf(" ");
}
}
}
}
n++;
i++;
 
nptr = eptr;
}
}
if (buf) {
/* did we read all data in the string? */
/* check if there is some additional stuff at the end of the file */
while (isspace(*nptr) || *nptr == '#') {
int c = getc(fp);
if (*nptr == '#')
if (c != EOF)
nptr = skip_comment(nptr);
if (c != '\n' && getc(fp) != EOF)
else
fprintf(stderr, "%s: %s: Warning: The file may contain more data than specified by the samples or cmp_size parameter.\n",
nptr = skip_space(nptr);
PROGRAM_NAME, file_name);
}
 
if (*nptr != '\0') {
 
fprintf(stderr, "%s: %s: Warning: The file may contain more data than specified by the samples or cmp_size parameter.\n",
 
PROGRAM_NAME, file_name);
}
}
fclose(fp);
return i;
 
}
 
 
 
/**
 
* @brief reads n_word words of a hex-encoded uint8_t data form a file to a
 
* buffer
 
*
 
* @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage
 
* return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a
 
* sequence are used as separators. If a string contains more than three hexadecimal
 
* numeric characters (0123456789abcdefABCDEF) in a row without separators, a
 
* separator is added after every second hexadecimal numeric character.
 
* Comments after a '#' symbol until the end of the line are ignored.
 
* E.g. "# comment\n ABCD 1 2\n34B 12\n" are interpreted as {0xAB, 0xCD,
 
* 0x01, 0x02, 0x34, 0x0B, 0x12}.
 
*
 
* @param file_name data/model file name
 
* @param buf buffer to write the file content (can be NULL)
 
* @param n_word number of uint8_t data words to read in
 
* @param verbose_en print verbose output if not zero
 
*
 
* @returns the size in bytes to store the file content; negative on error
 
*/
 
 
ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int verbose_en)
 
{
 
FILE *fp;
 
char *file_cpy = NULL;
 
long file_size;
 
ssize_t size;
if (n == 0)
if (!file_name)
 
abort();
 
 
errno = 0;
 
fp = fopen(file_name, "r");
 
if (fp == NULL) {
 
goto fail;
 
}
 
 
/* Get the number of bytes */
 
if (fseek(fp, 0L, SEEK_END) != 0)
 
goto fail;
 
file_size = ftell(fp);
 
if (file_size < 0)
 
goto fail;
 
if (file_size == 0) {
fprintf(stderr, "%s: %s: Warning: The file is empty.\n", PROGRAM_NAME, file_name);
fprintf(stderr, "%s: %s: Warning: The file is empty.\n", PROGRAM_NAME, file_name);
if (verbose_en && buf)
fclose(fp);
printf("\n\n");
return 0;
 
}
 
/* reset the file position indicator to the beginning of the file */
 
if (fseek(fp, 0L, SEEK_SET) != 0)
 
goto fail;
 
 
file_cpy = (char *)calloc(file_size+1, sizeof(char));
 
if (file_cpy == NULL) {
 
fprintf(stderr, "%s: %s: Error: allocating memory!\n", PROGRAM_NAME, file_name);
 
goto fail;
 
}
return n;
/* copy all the text into the file_cpy buffer */
 
size_t ret_code = fread(file_cpy, sizeof(char), file_size, fp);
 
if(ret_code != (size_t)file_size) {
 
if (feof(fp))
 
printf("%s: %s: Error: unexpected end of file.\n", PROGRAM_NAME, file_name);
 
goto fail;
 
}
 
/* just to be save we have a zero terminated string */
 
file_cpy[file_size] = '\0';
error:
fclose(fp);
fclose(fp);
 
fp = NULL;
 
 
size = str2uint8_arr(file_cpy, buf, n_word, file_name, verbose_en);
 
 
free(file_cpy);
 
file_cpy = NULL;
 
 
return size;
 
fail:
 
if (errno)
 
fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name,
 
strerror(errno));
 
if (fp)
 
fclose(fp);
 
free(file_cpy);
return -1;
return -1;
}
}
@@ -1051,9 +1207,6 @@ error:
@@ -1051,9 +1207,6 @@ error:
* @brief reads the number of uint16_t samples of a hex-encoded data (or model)
* @brief reads the number of uint16_t samples of a hex-encoded data (or model)
* file into a buffer
* file into a buffer
*
*
* @note data must be encoded as 2 hex digits separated by a white space or new
* line character e.g. "AB CD 12 34 AB 12\n"
*
* @param file_name data/model file name
* @param file_name data/model file name
* @param buf buffer to write the file content (can be NULL)
* @param buf buffer to write the file content (can be NULL)
* @param samples amount of uint16_t data samples to read in
* @param samples amount of uint16_t data samples to read in
@@ -1092,9 +1245,6 @@ ssize_t read_file16(const char *file_name, uint16_t *buf, uint32_t samples,
@@ -1092,9 +1245,6 @@ ssize_t read_file16(const char *file_name, uint16_t *buf, uint32_t samples,
* @brief reads the number of uint32_t samples of a hex-encoded data (or model)
* @brief reads the number of uint32_t samples of a hex-encoded data (or model)
* file into a buffer
* file into a buffer
*
*
* @note data must be encoded as 2 hex digits separated by a white space or new
* line character e.g. "AB CD 12 34 AB 12\n"
*
* @param file_name data/model file name
* @param file_name data/model file name
* @param buf buffer to write the file content (can be NULL)
* @param buf buffer to write the file content (can be NULL)
* @param samples amount of uint32_t data samples to read in
* @param samples amount of uint32_t data samples to read in
Loading