Here's the standard C version:
#include <stdlib.h>
#include <stdio.h>
/* Convert a hex digit to decimal value.
Returns -1 if the character is not a hex digit.
*/
static inline signed char hexdigit(const 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;
}
/* Convert a string of hex quads to UTF-8.
Returns the number of bytes in the result,
or -1 if an error occurs.
*/
int hex4_utf8(char *dst, char *src)
{
int d, c, n = 0;
if (!src)
return -1;
while (*src) {
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c = d << 12;
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c += d << 8;
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c += d << 4;
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c += d;
if (c < 128) {
if (dst) {
dst[n++] = c;
} else
n++;
} else
if (c < 2048) {
if (dst) {
dst[n++] = 192 + (c >> 6);
dst[n++] = 128 + (c & 63);
} else
n += 2;
} else {
if (dst) {
dst[n++] = 224 + (c >> 12);
dst[n++] = 128 + ((c >> 6) & 63);
dst[n++] = 128 + (c & 63);
} else
n += 3;
}
}
if (dst)
dst[n] = '\0';
return n;
}
int main(int argc, char *argv[])
{
char *dst = NULL;
int max = 0;
int arg, len, tmp;
for (arg = 1; arg < argc; arg++) {
len = hex4_utf8(dst, argv[arg]);
if (len < 0) {
fprintf(stderr, "%s: Not a hex string.\n", argv[arg]);
return EXIT_FAILURE;
}
if (len >= max) {
free(dst);
dst = malloc(len + 1);
if (!dst) {
fprintf(stderr, "Out of memory.\n");
return EXIT_FAILURE;
}
tmp = hex4_utf8(dst, argv[arg]);
if (tmp != len) {
fprintf(stderr, "%s: BUG: String modified unexpectedly.\n", argv[arg]);
return EXIT_FAILURE;
}
}
printf("%s = %s\n", argv[arg], dst);
}
return EXIT_SUCCESS;
}
You only need the hex4_utf8(destination, source) and hexdigit(character) functions. They do not need any library support, and will work even in freestanding mode (without the C library, no <stdlib.h> or <stdio.h> needed). Only the example main() uses <stdlib.h> and <stdio.h>.
The destination string will have at most 3/4 of the bytes of the source string (excluding the nul end-of-string; each quad of hex digits converts to one-, two-, or three-byte UTF-8 character), and it can do the conversion in place.
If you do not need the number of bytes in the result, and you never call hex4_utf8() with a NULL destination, I suggest that in Keil, you try something like
#include <stdio.h>
static inline signed char hexdigit(const 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;
}
int hex4_utf8(char *dst, char *src)
{
int d, c;
while (*src) {
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c = d << 12;
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c += d << 8;
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c += d << 4;
d = hexdigit(*(src++));
if (d < 0)
return -1;
else
c += d;
if (c < 128) {
*(dst++) = c;
} else
if (c < 2048) {
*(dst++) = 192 + (c >> 6);
*(dst++) = 128 + (c & 63);
} else {
*(dst++) = 224 + (c >> 12);
*(dst++) = 128 + ((c >> 6) & 63);
*(dst++) = 128 + (c & 63);
}
}
*dst = '\0';
return 0;
}
void main(void)
{
char msg[] = "0627064A06310627064606330644";
int n;
if (hex4_utf8(msg, msg) < 0) {
printf("Failed!\n");
} else {
printf("%s\n", msg);
for (n = 0; msg[n] != '\0'; n++)
printf("msg[%d] = %02x\n", n, msg[n]);
}
while (1) ;
}
It should output
ايرانسل
msg[0] = d8
msg[1] = a7
msg[2] = d9
msg[3] = 8a
msg[4] = d8
msg[5] = b1
msg[6] = d8
msg[7] = a7
msg[8] = d9
msg[9] = 86
msg[10] = d8
msg[11] = b3
msg[12] = d9
msg[13] = 84
However, I don't have the Keil C compiler, and I'm too lazy to install anything, so you'll have to test it yourself. I have only verified that the hexdigit() and hex4_utf8() functions work as expected.