static int parse_line(struct parser_context *ctx, const char *line) { unsigned int length, type; uint32_t address; uint8_t checksum; int r; ctx->ptr = line; ctx->sum = 0; ctx->error = false; // Empty lines are probably OK if (*ctx->ptr++ != ':') return 0; if (strlen(ctx->ptr) < 11) return parse_error(ctx); length = parse_hex_byte(ctx, true); address = parse_hex_short(ctx); type = parse_hex_byte(ctx, true); if (ctx->error) return parse_error(ctx); switch (type) { case 0: // data record address += ctx->base_offset; r = _ty_firmware_expand_image(ctx->fw, address + length); if (r < 0) return r; for (unsigned int i = 0; i < length; i++) ctx->fw->image[address + i] = parse_hex_byte(ctx, true); break; case 1: // EOF record if (length > 0) return parse_error(ctx); break; case 2: // extended segment address record if (length != 2) return parse_error(ctx); ctx->base_offset = (uint32_t)parse_hex_short(ctx) << 4; break; case 3: // start segment address record break; case 4: // extended linear address record if (length != 2) return parse_error(ctx); ctx->base_offset = (uint32_t)parse_hex_short(ctx) << 16; break; case 5: // start linear address record break; default: return parse_error(ctx); } // Don't checksum the checksum :) checksum = parse_hex_byte(ctx, false); if (ctx->error) return parse_error(ctx); if (*ctx->ptr != '\r' && *ctx->ptr != '\n' && *ctx->ptr) return parse_error(ctx); if (((ctx->sum & 0xFF) + (checksum & 0xFF)) & 0xFF) return parse_error(ctx); // Return 1 for EOF records, to end the parsing return type == 1; }
static int parse_line(struct parser_context *ctx, const char *line) { unsigned int length, type; uint32_t address; uint8_t checksum; ctx->ptr = line; ctx->sum = 0; ctx->error = false; // Empty lines are probably OK if (*ctx->ptr++ != ':') return 1; if (strlen(ctx->ptr) < 11) return TY_ERROR_PARSE; length = parse_hex_byte(ctx, true); address = parse_hex_short(ctx); type = parse_hex_byte(ctx, true); if (ctx->error) return TY_ERROR_PARSE; switch (type) { case 0: // data record address += ctx->base_offset; if (address + length > ctx->f->size) { ctx->f->size = address + length; if (ctx->f->size > tyb_firmware_max_size) return ty_error(TY_ERROR_RANGE, "Firmware too big (max %zu bytes)", tyb_firmware_max_size); } for (unsigned int i = 0; i < length; i++) ctx->f->image[address + i] = parse_hex_byte(ctx, true); break; case 1: // EOF record if (length > 0) return TY_ERROR_PARSE; return 0; case 2: // extended segment address record if (length != 2) return TY_ERROR_PARSE; ctx->base_offset = (uint32_t)parse_hex_short(ctx) << 4; break; case 3: // start segment address record break; case 4: // extended linear address record if (length != 2) return TY_ERROR_PARSE; ctx->base_offset = (uint32_t)parse_hex_short(ctx) << 16; break; case 5: // start linear address record break; default: return TY_ERROR_PARSE; } // Don't checksum the checksum :) checksum = parse_hex_byte(ctx, false); if (ctx->error) return TY_ERROR_PARSE; if (((ctx->sum & 0xFF) + (checksum & 0xFF)) & 0xFF) return TY_ERROR_PARSE; // 1 to continue, 0 to stop (EOF record) and negative for errors return 1; }