#include "firmware_image.h" #include static int hex_digit(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c - 'A' + 10; if (c >= 'a' && c <= 'f') return c - 'a' + 10; return -1; } static int space(char c) { return c == ' ' || c == '\t' || c == '\r'; } static int compare_cells(const void *a, const void *b) { uint32_t x = ((const firmware_hex_cell_t *)a)->address; uint32_t y = ((const firmware_hex_cell_t *)b)->address; return (x > y) - (x < y); } int firmware_hex_parse(const char *text, size_t length, firmware_hex_cell_t *cells, size_t capacity, size_t max_records, size_t *count, size_t *error_line) { size_t pos = 0, line = 0, used = 0, records = 0, i; uint32_t upper = 0; int eof = 0; if (count == NULL || error_line == NULL) return FW_HEX_FORMAT; *count = 0; *error_line = 0; if (text == NULL || cells == NULL) return FW_HEX_FORMAT; while (pos < length) { size_t begin = pos, end, n; uint8_t bytes[260]; unsigned sum = 0, size, kind, address; while (pos < length && text[pos] != '\n') ++pos; end = pos; if (pos < length) ++pos; ++line; while (begin < end && space(text[begin])) ++begin; while (end > begin && space(text[end-1])) --end; if (begin == end) continue; *error_line = line; if (eof) return FW_HEX_EOF; if (++records > max_records) return FW_HEX_CAPACITY; if (text[begin++] != ':') return FW_HEX_PREFIX; if ((end-begin) & 1U) return FW_HEX_DIGITS; n = (end-begin)/2; if (n < 5 || n > sizeof(bytes)) return FW_HEX_FORMAT; for (i = 0; i < n; ++i) { int hi = hex_digit(text[begin+2*i]), lo = hex_digit(text[begin+2*i+1]); if (hi < 0 || lo < 0) return FW_HEX_DIGITS; bytes[i] = (uint8_t)(hi*16+lo); sum += bytes[i]; } size = bytes[0]; address = ((unsigned)bytes[1]<<8) | bytes[2]; kind = bytes[3]; if (n != size+5U) return FW_HEX_LENGTH; if (sum & 255U) return FW_HEX_CHECKSUM; if (kind == 0) { uint64_t absolute = (uint64_t)upper + address; if (size && absolute + size - 1 > UINT32_MAX) return FW_HEX_RANGE; if (size > capacity-used) return FW_HEX_CAPACITY; for (i = 0; i < size; ++i) { cells[used].address = (uint32_t)(absolute+i); cells[used++].value = bytes[4+i]; } } else if (kind == 1) { if (size || address) return FW_HEX_RECORD; eof = 1; } else if (kind == 2 || kind == 4) { if (size != 2 || address) return FW_HEX_RECORD; upper = ((uint32_t)bytes[4]<<8) | bytes[5]; upper <<= kind == 2 ? 4 : 16; } else if (kind == 3 || kind == 5) { if (size != 4 || address) return FW_HEX_RECORD; } else return FW_HEX_RECORD; } if (!eof || !used) return FW_HEX_EOF; qsort(cells, used, sizeof(*cells), compare_cells); for (i = 1; i < used; ++i) if (cells[i-1].address == cells[i].address) { *error_line = 0; return FW_HEX_OVERLAP; } *count = used; *error_line = 0; return FW_HEX_OK; } size_t firmware_hex_segment_size(const firmware_hex_cell_t *cells, size_t count, size_t offset) { size_t end; if (cells == NULL || offset >= count) return 0; end = offset+1; while (end < count && cells[end-1].address != UINT32_MAX && cells[end].address == cells[end-1].address+1U) ++end; return end-offset; }