#include "hex-parser.h"
#include <stddef.h>

static int convert_hex_char_to_value(char c, uint32_t *out)
{
        int ret = 0;
        uint32_t value = 0;

        if (!out)
                return -1002;

        switch (c) {
        case '0' ... '9':
                value = (uint32_t)c - (uint32_t)'0';
                break;
        case 'a' ... 'f':
                /* Convert to upper */
                c -= 0x20;
                /* FALLTHRU */
        case 'A' ... 'F':
                value = (uint32_t)c - (uint32_t)'A' + 10UL;
                break;
        default:
                ret = -1;
        }

        if (ret == 0)
                *out = value;

        return ret;
}

static int convert_big_endian_hex_string_to_val(const char *string, size_t len, uint32_t *out)
{
        int ret_val = -1;
        uint32_t converted_value = 0UL;
        uint32_t digit;
        int res;
        unsigned int i;

        /* Return error in case of an input error */
        if (!string || !len)
                goto exit;

        if (!out)
                return -1003;

        /* we don't support strings larger than 8 chars */
        if (len > 8)
                goto exit;


        for (i = 0; i < len && string[i] != '\0'; i++) {
                /* Convert current character to number */
                res = convert_hex_char_to_value(string[i], &digit);
                if (res) {
                        /* Not a hex number */
                        ret_val = -2;
                        goto exit;
                }

                converted_value *= 0x10;
                converted_value += digit;
        }

        *out = converted_value;

exit:
        return ret_val;
}

enum hex_parser_ret hex_parser_open(struct hex_parser *parser, const char *file_name)
{
	FRESULT fres;

	if (!parser || !file_name)
		return HEX_PARSER_ERROR;

	parser->current_address_offset = 0UL;
	fres = f_open(&parser->file, file_name, FA_READ);
	if (fres != FR_OK) {
		return HEX_PARSER_ERROR;
	}

	return HEX_PARSER_OK;
}

enum hex_parser_ret hex_parser_parse(struct hex_parser *parser, uint32_t *address, char *data, size_t data_len);

enum hex_parser_ret hex_parser_close(struct hex_parser *parser) {
	if (!parser)
		return HEX_PARSER_ERROR;
	f_close(&parser->file);
	return HEX_PARSER_OK;
}
