/*
 *
 * (c) Copyright 2015 Samsung Research America, Inc.
 *                  All rights reserved
 *
 *                  MCL-B2B Lab
 *
 *
 * File: utils.c
 * Author: r.kadir@samsung.com
 * Creation Date: Apr, 2015
 *
 */
/**
* Copyright (C) 2015 Samsung Electronics Co., Ltd. All rights reserved.
*
* Mobile Platform & Solutions Lab (MPS Lab),
* Samsung Electronics Co., Ltd.
*
* This software and its documentation are confidential and proprietary
* information of Samsung Electronics Co., Ltd.  No part of the software and
* documents may be copied, reproduced, transmitted, translated, or reduced to
* any electronic medium or machine-readable form without the prior written
* consent of Samsung Electronics.
*
* Samsung Electronics makes no representations with respect to the contents,
* and assumes no responsibility for any errors that might appear in the
* software and documents. This publication and the contents hereof are subject
* to change without notice.
*/
#include <stdio.h>
#include "coldwallet_errors.h"
#include "TZ_Vendor_debug_tl.h"
#include "utils.h"

static uint8_t hexMapLower[] =
    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};

static uint8_t hexMapUpper[] =
    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

static int32_t hexMapLen = sizeof(hexMapLower);

uint8_t tohexchar(
    uint8_t nibble,
    uint8_t isUpper
)
{
    if (nibble < hexMapLen) {
        if (isUpper)
            return hexMapLower[nibble];
        else
            return hexMapUpper[nibble];
    }
    return '*';
}

uint8_t fromhexchar(
    uint8_t 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 255;
}

//////////////////////////////////////////////
///////////////////////////////////////////////

void tobytes(
	uint8_t * hexstr,
	uint32_t hexstrlen,
	uint8_t * bytes
)
{
	if (hexstr == 0)
		return;

	int32_t i = 0;
	for (i = 0; i < hexstrlen; i += 2) {
		bytes[i / 2] =
		    (fromhexchar(hexstr[i]) << 4) | fromhexchar(hexstr[i + 1]);
	}

	if (hexstrlen % 2) {
		bytes[i / 2] =
		    (fromhexchar(hexstr[i]) << 4) | fromhexchar(hexstr[i + 1]);
	}
}

void tohexstring(
	uint8_t * bytes,
	int32_t byteslen,
	uint8_t * hexstring,
	uint8_t isUpper
)
{
	int32_t i = 0;
	for (i = 0; i < byteslen; i++) {
		hexstring[i * 2] = tohexchar((bytes[i] & 0xf0) >> 4, isUpper);
		hexstring[i * 2 + 1] = tohexchar(bytes[i] & 0x0f, isUpper);
	}
}

uint32_t convertStringToInteger(
	uint8_t * s
)
{
	uint32_t num = 0;
	uint32_t i = 0;
	uint8_t digit;

	while (s[i] != 0) {
		if (s[i] < '0' && s[i] > '9')
			return 0;

		digit = s[i] - '0';
		num = (num * 10) + digit;
		i++;
	}
	return num;
}

#define FROMHEX_MAXLEN 512

uint8_t *fromhex(const char *str)
{
    static uint8_t buf[FROMHEX_MAXLEN];
    size_t len = strlen(str) / 2;
    if (len > FROMHEX_MAXLEN) len = FROMHEX_MAXLEN;
    for (size_t i = 0; i < len; i++) {
        uint8_t c = 0;
        if (str[i * 2] >= '0' && str[i * 2] <= '9') c += (str[i * 2] - '0') << 4;
        if ((str[i * 2] & ~0x20) >= 'A' && (str[i * 2] & ~0x20) <= 'F') c += (10 + (str[i * 2] & ~0x20) - 'A') << 4;
        if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') c += (str[i * 2 + 1] - '0');
        if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F') c += (10 + (str[i * 2 + 1] & ~0x20) - 'A');
        buf[i] = c;
    }
    return buf;
}

void utils_hex_to_bin(const char* str, unsigned char* out, int inLen, int* outLen)
{
    int bLen = inLen / 2;
    //uint8_t c;
    int i;
    memset(out, 0, bLen);
    for (i = 0; i < bLen; i++) {
        //c = 0;
        if (str[i * 2] >= '0' && str[i * 2] <= '9') {
            *out = (str[i * 2] - '0') << 4;
        }
        if (str[i * 2] >= 'a' && str[i * 2] <= 'f') {
            *out = (10 + str[i * 2] - 'a') << 4;
        }
        if (str[i * 2] >= 'A' && str[i * 2] <= 'F') {
            *out = (10 + str[i * 2] - 'A') << 4;
        }
        if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') {
            *out |= (str[i * 2 + 1] - '0');
        }
        if (str[i * 2 + 1] >= 'a' && str[i * 2 + 1] <= 'f') {
            *out |= (10 + str[i * 2 + 1] - 'a');
        }
        if (str[i * 2 + 1] >= 'A' && str[i * 2 + 1] <= 'F') {
            *out |= (10 + str[i * 2 + 1] - 'A');
        }
        out++;
    }
    *outLen = i;
}

void utils_bin_to_hex(unsigned char* bin_in, size_t inlen, char* hex_out, size_t outlen)
{
    static char digits[] = "0123456789abcdef";
    size_t i;
    if(inlen*2 < outlen) {
        for (i = 0; i < inlen; i++) {
            hex_out[i * 2] = digits[(bin_in[i] >> 4) & 0xF];
            hex_out[i * 2 + 1] = digits[bin_in[i] & 0xF];
        }
        hex_out[inlen * 2] = '\0';
    }
}

uint32_t safe_sprintf_append(uint16_t cur_len, uint16_t limit, char *str, const char *format, ...) {
    if (limit - cur_len <= 0) {
        TTY_LOG("safe_sprintf_append:buffer_full. %d, %d", limit, cur_len);
        return COLDWALLET_INTERNAL_ERR;
    }
    va_list args;
    va_start(args, format);
    int result = vsnprintf(str, limit - cur_len, format, args);
    va_end(args);
    if (result + cur_len > limit) {
        TTY_LOG("safe_sprintf_append:buffer_overflow. %d_%d_%d", result, cur_len, limit);
        return COLDWALLET_INTERNAL_ERR;
    }
    return COLDWALLET_OK;
}
