summaryrefslogtreecommitdiffhomepage
path: root/src/load.c
diff options
context:
space:
mode:
authormimaki <[email protected]>2012-04-20 09:39:03 +0900
committermimaki <[email protected]>2012-04-20 09:39:03 +0900
commite0d6430f63c4cbe0c71ce82ee23284671389a818 (patch)
tree41abad7f12eced98d9ac14d141cea62464c3332f /src/load.c
parent54ad561098ed353ada70205c39b2c42a2a2eb9e5 (diff)
downloadmruby-e0d6430f63c4cbe0c71ce82ee23284671389a818.tar.gz
mruby-e0d6430f63c4cbe0c71ce82ee23284671389a818.zip
add mruby sources
Diffstat (limited to 'src/load.c')
-rw-r--r--src/load.c642
1 files changed, 642 insertions, 0 deletions
diff --git a/src/load.c b/src/load.c
new file mode 100644
index 000000000..848cf8f9a
--- /dev/null
+++ b/src/load.c
@@ -0,0 +1,642 @@
+#include <string.h>
+#include "dump.h"
+
+#include "mruby/string.h"
+#ifdef INCLUDE_REGEXP
+#include "re.h"
+#endif
+#include "irep.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+typedef struct _RiteFILE
+{
+ FILE* fp;
+ unsigned char buf[256];
+ int cnt;
+ int readlen;
+} RiteFILE;
+
+const char hex2bin[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //00-0f
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10-1f
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-2f
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, //30-3f
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40-4f
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50-5f
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0 //60-6f
+ //70-ff
+};
+
+static uint16_t hex_to_bin8(unsigned char*,unsigned char*);
+static uint16_t hex_to_bin16(unsigned char*,unsigned char*);
+static uint16_t hex_to_bin32(unsigned char*,unsigned char*);
+static uint8_t hex_to_uint8(unsigned char*);
+static uint16_t hex_to_uint16(unsigned char*);
+static uint32_t hex_to_uint32(unsigned char*);
+static char* hex_to_str(char*,char*,uint16_t*);
+uint16_t calc_crc_16_ccitt(unsigned char*,int);
+static unsigned char rite_fgetcSub(RiteFILE*);
+static unsigned char rite_fgetc(RiteFILE*,int);
+static unsigned char* rite_fgets(RiteFILE*,unsigned char*,int,int);
+static int load_rite_header(FILE*,rite_binary_header*,unsigned char*);
+static int load_rite_irep_record(mrb_state*, RiteFILE*,unsigned char*,uint32_t*);
+static int read_rite_header(mrb_state*,unsigned char*,rite_binary_header*);
+static int read_rite_irep_record(mrb_state*,unsigned char*,mrb_irep*,uint32_t*);
+
+
+static unsigned char
+rite_fgetcSub(RiteFILE* rfp)
+{
+ //only first call
+ if (rfp->buf[0] == '\0') {
+ rfp->readlen = fread(rfp->buf, 1, sizeof(rfp->buf), rfp->fp);
+ rfp->cnt = 0;
+ }
+
+ if (rfp->readlen == rfp->cnt) {
+ rfp->readlen = fread(rfp->buf, 1, sizeof(rfp->buf), rfp->fp);
+ rfp->cnt = 0;
+ if (rfp->readlen == 0) {
+ return '\0';
+ }
+ }
+ return rfp->buf[(rfp->cnt)++];
+}
+
+static unsigned char
+rite_fgetc(RiteFILE* rfp, int ignorecomment)
+{
+ unsigned char tmp;
+
+ for (;;) {
+ tmp = rite_fgetcSub(rfp);
+ if (tmp == '\n' || tmp == '\r') {
+ continue;
+ }
+ else if (ignorecomment && tmp == '#') {
+ while (tmp != '\n' && tmp != '\r' && tmp != '\0')
+ tmp = rite_fgetcSub(rfp);
+ if (tmp == '\0')
+ return '\0';
+ }
+ else {
+ return tmp;
+ }
+ }
+}
+
+static unsigned char*
+rite_fgets(RiteFILE* rfp, unsigned char* dst, int len, int ignorecomment)
+{
+ int i;
+
+ for (i=0; i<len; i++) {
+ if ('\0' == (dst[i] = rite_fgetc(rfp, ignorecomment))) {
+ return NULL;
+ }
+ }
+ return dst;
+}
+
+static int
+load_rite_header(FILE* fp, rite_binary_header* bin_header, unsigned char* hcrc)
+{
+ rite_file_header file_header;
+
+ fread(&file_header, 1, sizeof(file_header), fp);
+ memcpy(bin_header->rbfi, file_header.rbfi, sizeof(file_header.rbfi));
+ if (memcmp(bin_header->rbfi, RITE_FILE_IDENFIFIER, sizeof(bin_header->rbfi)) != 0) {
+ return MRB_DUMP_INVALID_FILE_HEADER; //File identifier error
+ }
+ memcpy(bin_header->rbfv, file_header.rbfv, sizeof(file_header.rbfv));
+ if (memcmp(bin_header->rbfv, RITE_FILE_FORMAT_VER, sizeof(bin_header->rbfv)) != 0) {
+ return MRB_DUMP_INVALID_FILE_HEADER; //File format version error
+ }
+ memcpy(bin_header->risv, file_header.risv, sizeof(file_header.risv));
+ memcpy(bin_header->rct, file_header.rct, sizeof(file_header.rct));
+ memcpy(bin_header->rcv, file_header.rcv, sizeof(file_header.rcv));
+ hex_to_bin32(bin_header->rbds, file_header.rbds);
+ hex_to_bin16(bin_header->nirep, file_header.nirep);
+ hex_to_bin16(bin_header->sirep, file_header.sirep);
+ memcpy(bin_header->rsv, file_header.rsv, sizeof(file_header.rsv));
+ memcpy(hcrc, file_header.hcrc, sizeof(file_header.hcrc));
+
+ return MRB_DUMP_OK;
+}
+
+static int
+load_rite_irep_record(mrb_state *mrb, RiteFILE* rfp, unsigned char* dst, uint32_t* len)
+{
+ int i;
+ uint32_t blocklen;
+ uint16_t offset, tt, pdl, snl, clen;
+ unsigned char hex2[2], hex4[4], hex8[8], hcrc[4];
+ unsigned char *pStart;
+ char *char_buf;
+ uint16_t buf_size =0;
+
+ buf_size = MRB_DUMP_DEFAULT_STR_LEN;
+ if ((char_buf = mrb_malloc(mrb, buf_size)) == 0)
+ goto error_exit;
+
+ pStart = dst;
+
+ //IREP HEADER BLOCK
+ *dst = rite_fgetc(rfp, TRUE); //record identifier
+ if (*dst != RITE_IREP_IDENFIFIER)
+ return MRB_DUMP_INVALID_IREP;
+ dst += sizeof(unsigned char);
+ *dst = rite_fgetc(rfp, TRUE); //class or module
+ dst += sizeof(unsigned char);
+ rite_fgets(rfp, hex4, sizeof(hex4), TRUE); //number of local variable
+ dst += hex_to_bin16(dst, hex4);
+ rite_fgets(rfp, hex4, sizeof(hex4), TRUE); //number of register variable
+ dst += hex_to_bin16(dst, hex4);
+ rite_fgets(rfp, hex4, sizeof(hex4), TRUE); //offset of isec block
+ offset = hex_to_uint16(hex4);
+ rite_fgets(rfp, hcrc, sizeof(hcrc), TRUE); //header CRC
+ memset( char_buf, '\0', buf_size);
+ rite_fgets(rfp, (unsigned char*)char_buf, (offset - (MRB_DUMP_SIZE_OF_SHORT * RITE_FILE_HEX_SIZE)), TRUE); //class or module name
+ hex_to_str(char_buf, (char*)(dst + MRB_DUMP_SIZE_OF_SHORT + MRB_DUMP_SIZE_OF_SHORT), &clen); //class or module name
+ dst += uint16_to_bin((MRB_DUMP_SIZE_OF_SHORT/*crc*/ + clen), (char*)dst); //offset of isec block
+ dst += hex_to_bin16(dst, hcrc); //header CRC
+ dst += clen;
+
+ //ISEQ BLOCK
+ rite_fgets(rfp, hex8, sizeof(hex8), TRUE); //iseq length
+ dst += hex_to_bin32(dst, hex8);
+ blocklen = hex_to_uint32(hex8);
+ for (i=0; i<blocklen; i++) {
+ rite_fgets(rfp, hex8, sizeof(hex8), TRUE); //iseq
+ dst += hex_to_bin32(dst, hex8);
+ }
+ rite_fgets(rfp, hcrc, sizeof(hcrc), TRUE); //iseq CRC
+ dst += hex_to_bin16(dst, hcrc);
+
+ //POOL BLOCK
+ rite_fgets(rfp, hex8, sizeof(hex8), TRUE); //pool length
+ dst += hex_to_bin32(dst, hex8);
+ blocklen = hex_to_uint32(hex8);
+ for (i=0; i<blocklen; i++) {
+ rite_fgets(rfp, hex2, sizeof(hex2), TRUE); //TT
+ dst += hex_to_bin8(dst, hex2);
+ tt = hex_to_uint8(hex2);
+ rite_fgets(rfp, hex4, sizeof(hex4), TRUE); //pool data length
+ pdl = hex_to_uint16(hex4);
+
+ if ( pdl > buf_size - 1) {
+ buf_size = pdl + 1;
+ if ((char_buf = mrb_realloc(mrb, char_buf, buf_size)) == 0)
+ goto error_exit;
+ }
+ memset(char_buf, '\0', buf_size);
+ rite_fgets(rfp, (unsigned char*)char_buf, pdl, FALSE); //pool
+ hex_to_str(char_buf, (char*)(dst + MRB_DUMP_SIZE_OF_SHORT), &clen);
+ dst += uint16_to_bin(clen, (char*)dst);
+ dst += clen;
+ }
+ rite_fgets(rfp, hcrc, sizeof(hcrc), TRUE); //pool CRC
+ dst += hex_to_bin16(dst, hcrc);
+
+ //SYMS BLOCK
+ rite_fgets(rfp, hex8, sizeof(hex8), TRUE); //syms length
+ dst += hex_to_bin32(dst, hex8);
+ blocklen = hex_to_uint32(hex8);
+ for (i=0; i<blocklen; i++) {
+ rite_fgets(rfp, hex4, sizeof(hex4), TRUE); //symbol name length
+ snl = hex_to_uint16(hex4);
+
+ if (snl == MRB_DUMP_NULL_SYM_LEN) {
+ dst += uint16_to_bin(snl, (char*)dst);
+ continue;
+ }
+
+ if ( snl > buf_size - 1) {
+ buf_size = snl + 1;
+ if ((char_buf = mrb_realloc(mrb, char_buf, buf_size)) == 0)
+ goto error_exit;
+ }
+ memset(char_buf, '\0', buf_size);
+ rite_fgets(rfp, (unsigned char*)char_buf, snl, FALSE); //symbol name
+ hex_to_str(char_buf, (char*)(dst + MRB_DUMP_SIZE_OF_SHORT), &clen);
+ dst += uint16_to_bin(clen, (char*)dst);
+ dst += clen;
+ }
+ rite_fgets(rfp, hcrc, sizeof(hcrc), TRUE); //syms CRC
+ dst += hex_to_bin16(dst, hcrc);
+
+ *len = dst - pStart;
+
+error_exit:
+ if (char_buf)
+ mrb_free(mrb, char_buf);
+
+ return MRB_DUMP_OK;
+}
+
+int
+mrb_load_irep(mrb_state *mrb, FILE* fp)
+{
+ int ret, i;
+ uint32_t len, rlen;
+ unsigned char hex8[8], hcrc[4];
+ unsigned char *dst, *rite_dst = NULL;
+ rite_binary_header bin_header;
+ RiteFILE ritefp, *rfp;
+
+ if ((mrb == NULL) || (fp == NULL)) {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ memset(&ritefp, 0, sizeof(ritefp));
+ ritefp.fp = fp;
+ rfp = &ritefp;
+
+ //Read File Header Section
+ if ((ret = load_rite_header(fp, &bin_header, hcrc)) != MRB_DUMP_OK)
+ return ret;
+
+ len = sizeof(rite_binary_header) + bin_to_uint32(bin_header.rbds);
+ if ((rite_dst = mrb_malloc(mrb, len)) == NULL)
+ return MRB_DUMP_GENERAL_FAILURE;
+
+ dst = rite_dst;
+ memset(dst, 0x00, len);
+ memcpy(dst, &bin_header, sizeof(rite_binary_header));
+ dst += sizeof(rite_binary_header);
+ dst += hex_to_bin16(dst, hcrc);
+
+ //Read Binary Data Section
+ len = bin_to_uint16(bin_header.nirep);
+ for (i=0; i<len; i++) {
+ rite_fgets(rfp, hex8, sizeof(hex8), TRUE); //record len
+ dst += hex_to_bin32(dst, hex8);
+ if ((ret = load_rite_irep_record(mrb, rfp, dst, &rlen)) != MRB_DUMP_OK) //irep info
+ goto error_exit;
+ dst += rlen;
+ }
+ rite_fgets(rfp, hex8, sizeof(hex8), TRUE); //dummy record len
+ dst += hex_to_bin32(dst, hex8);
+ if (0 != hex_to_uint32(hex8)) {
+ ret = MRB_DUMP_INVALID_IREP;
+ goto error_exit;
+ }
+
+ if (ret == MRB_DUMP_OK)
+ ret = mrb_read_irep(mrb, (char*)rite_dst);
+
+error_exit:
+ if (rite_dst)
+ mrb_free(mrb, rite_dst);
+
+ return ret;
+}
+
+static int
+read_rite_header(mrb_state *mrb, unsigned char *bin, rite_binary_header* bin_header)
+{
+ uint16_t crc;
+
+ memcpy(bin_header, bin, sizeof(rite_binary_header));
+ bin += sizeof(rite_binary_header);
+ if (memcmp(bin_header->rbfi, RITE_FILE_IDENFIFIER, sizeof(bin_header->rbfi)) != 0) {
+ return MRB_DUMP_INVALID_FILE_HEADER; //File identifier error
+ }
+ if (memcmp(bin_header->risv, RITE_VM_VER, sizeof(bin_header->risv)) != 0) {
+ return MRB_DUMP_INVALID_FILE_HEADER; //Instruction set version check
+ }
+
+ crc = calc_crc_16_ccitt((unsigned char *)bin_header, sizeof(*bin_header)); //Calculate CRC
+ if (crc != bin_to_uint16(bin)) {
+ return MRB_DUMP_INVALID_FILE_HEADER; //CRC error
+ }
+
+ return bin_to_uint16(bin_header->nirep);
+}
+
+static int
+read_rite_irep_record(mrb_state *mrb, unsigned char *src, mrb_irep *irep, uint32_t* len)
+{
+ int i, ret = MRB_DUMP_OK;
+ char *buf;
+ unsigned char *recordStart, *pStart;
+ uint16_t crc, tt, pdl, snl, offset, bufsize=MRB_DUMP_DEFAULT_STR_LEN;
+ mrb_int fix_num;
+ mrb_float f;
+ mrb_value str;
+
+ recordStart = src;
+ buf = mrb_malloc(mrb, bufsize);
+ if (buf == NULL) {
+ ret = MRB_DUMP_INVALID_IREP;
+ goto error_exit;
+ }
+
+ //Header Section
+ pStart = src;
+ if (*src != RITE_IREP_IDENFIFIER)
+ return MRB_DUMP_INVALID_IREP;
+ src += (sizeof(unsigned char) * 2);
+ irep->nlocals = bin_to_uint16(src); //number of local variable
+ src += MRB_DUMP_SIZE_OF_SHORT;
+ irep->nregs = bin_to_uint16(src); //number of register variable
+ src += MRB_DUMP_SIZE_OF_SHORT;
+ offset = bin_to_uint16(src); //offset of isec block
+ src += MRB_DUMP_SIZE_OF_SHORT;
+ crc = calc_crc_16_ccitt(pStart, src - pStart); //Calculate CRC
+ if (crc != bin_to_uint16(src)) //header CRC
+ return MRB_DUMP_INVALID_IREP;
+ src += offset;
+
+ //Binary Data Section
+ //ISEQ BLOCK
+ pStart = src;
+ irep->ilen = bin_to_uint32(src); //iseq length
+ src += MRB_DUMP_SIZE_OF_LONG;
+ if (irep->ilen > 0) {
+ if ((irep->iseq = mrb_malloc(mrb, sizeof(mrb_code) * irep->ilen)) == NULL) {
+ ret = MRB_DUMP_GENERAL_FAILURE;
+ goto error_exit;
+ }
+ for (i=0; i<irep->ilen; i++) {
+ irep->iseq[i] = bin_to_uint32(src); //iseq
+ src += MRB_DUMP_SIZE_OF_LONG;
+ }
+ }
+ crc = calc_crc_16_ccitt((unsigned char *)pStart, src - pStart); //Calculate CRC
+ if (crc != bin_to_uint16(src)) { //iseq CRC
+ ret = MRB_DUMP_INVALID_IREP;
+ goto error_exit;
+ }
+ src += MRB_DUMP_SIZE_OF_SHORT;
+
+ //POOL BLOCK
+ pStart = src;
+ irep->plen = bin_to_uint32(src); //pool length
+ src += MRB_DUMP_SIZE_OF_LONG;
+ if (irep->plen > 0) {
+ irep->pool = mrb_malloc(mrb, sizeof(mrb_value) * irep->plen);
+ if (irep->pool == NULL) {
+ ret = MRB_DUMP_INVALID_IREP;
+ goto error_exit;
+ }
+
+ for (i=0; i<irep->plen; i++) {
+ tt = *src; //pool TT
+ src += sizeof(unsigned char);
+ pdl = bin_to_uint16(src); //pool data length
+ src += MRB_DUMP_SIZE_OF_SHORT;
+ if (pdl > bufsize - 1) {
+ mrb_free(mrb, buf);
+ bufsize = pdl + 1;
+ if ((buf = mrb_malloc(mrb, bufsize)) == NULL) {
+ ret = MRB_DUMP_GENERAL_FAILURE;
+ goto error_exit;
+ }
+ }
+ memcpy(buf, src, pdl);
+ src += pdl;
+ buf[pdl] = '\0';
+
+ switch (tt) { //pool data
+ case MRB_TT_FIXNUM:
+ sscanf(buf, "%d", &fix_num);
+ irep->pool[i] = mrb_fixnum_value(fix_num);
+ break;
+
+ case MRB_TT_FLOAT:
+ sscanf(buf, "%le", &f);
+ irep->pool[i] = mrb_float_value(f);
+ break;
+
+ case MRB_TT_STRING:
+ irep->pool[i] = mrb_str_new(mrb, buf, pdl);
+ break;
+
+#ifdef INCLUDE_REGEXP
+ case MRB_TT_REGEX:
+ str = mrb_str_new(mrb, buf, pdl);
+ irep->pool[i] = mrb_reg_quote(mrb, str);
+ break;
+#endif
+
+ default:
+ irep->pool[i] = mrb_nil_value();
+ break;
+ }
+ }
+ }
+ crc = calc_crc_16_ccitt((unsigned char *)pStart, src - pStart); //Calculate CRC
+ if (crc != bin_to_uint16(src)) { //pool CRC
+ ret = MRB_DUMP_INVALID_IREP;
+ goto error_exit;
+ }
+ src += MRB_DUMP_SIZE_OF_SHORT;
+
+ //SYMS BLOCK
+ pStart = src;
+ irep->slen = bin_to_uint32(src); //syms length
+ src += MRB_DUMP_SIZE_OF_LONG;
+ if (irep->slen > 0) {
+ if ((irep->syms = mrb_malloc(mrb, MRB_DUMP_SIZE_OF_INT * irep->slen)) == NULL) {
+ ret = MRB_DUMP_INVALID_IREP;
+ goto error_exit;
+ }
+
+ memset(irep->syms, 0, sizeof(mrb_sym)*(irep->slen));
+ for (i=0; i<irep->slen; i++) {
+ snl = bin_to_uint16(src); //symbol name length
+ src += MRB_DUMP_SIZE_OF_SHORT;
+
+ if (snl == MRB_DUMP_NULL_SYM_LEN) {
+ irep->syms[i] = 0;
+ continue;
+ }
+
+ if (snl > bufsize - 1) {
+ mrb_free(mrb, buf);
+ bufsize = snl + 1;
+ if ((buf = mrb_malloc(mrb, bufsize)) == NULL) {
+ ret = MRB_DUMP_GENERAL_FAILURE;
+ goto error_exit;
+ }
+ }
+ memcpy(buf, src, snl); //symbol name
+ src += snl;
+ buf[snl] = '\0';
+ irep->syms[i] = mrb_intern(mrb, buf);
+ }
+ }
+ crc = calc_crc_16_ccitt((unsigned char *)pStart, src - pStart); //Calculate CRC
+ if (crc != bin_to_uint16(src)) { //syms CRC
+ ret = MRB_DUMP_INVALID_IREP;
+ goto error_exit;
+ }
+ src += MRB_DUMP_SIZE_OF_SHORT;
+
+ *len = src - recordStart;
+error_exit:
+ if (buf)
+ mrb_free(mrb, buf);
+
+ return ret;
+}
+
+int
+mrb_read_irep(mrb_state *mrb, char *bin)
+{
+ int ret = MRB_DUMP_OK, i, n, nirep, sirep;
+ uint32_t len;
+ unsigned char *src;
+ rite_binary_header bin_header;
+
+ if ((mrb == NULL) || (bin == NULL)) {
+ return MRB_DUMP_INVALID_ARGUMENT;
+ }
+ src = (unsigned char*)bin;
+ sirep = mrb->irep_len;
+
+ //Read File Header Section
+ if ((nirep = read_rite_header(mrb, src, &bin_header)) < 0)
+ return nirep;
+
+ mrb_add_irep(mrb, sirep + nirep);
+
+ for (n=0,i=sirep; n<nirep; n++,i++) {
+ if ((mrb->irep[i] = mrb_malloc(mrb, sizeof(mrb_irep))) == NULL) {
+ ret = MRB_DUMP_GENERAL_FAILURE;
+ goto error_exit;
+ }
+ memset(mrb->irep[i], 0, sizeof(mrb_irep));
+ }
+ src += sizeof(bin_header) + MRB_DUMP_SIZE_OF_SHORT; //header + crc
+
+ //Read Binary Data Section
+ for (n=0,i=sirep; n<nirep; n++,i++) {
+ src += MRB_DUMP_SIZE_OF_LONG; //record ren
+ if ((ret = read_rite_irep_record(mrb, src, mrb->irep[i], &len)) != MRB_DUMP_OK)
+ goto error_exit;
+ mrb->irep[i]->idx = i;
+ src += len;
+ }
+ if (0 != bin_to_uint32(src)) { //dummy record len
+ ret = MRB_DUMP_GENERAL_FAILURE;
+ }
+
+ mrb->irep_len += nirep;
+
+error_exit:
+ if (ret != MRB_DUMP_OK) {
+ for (n=0,i=sirep; n<nirep; n++,i++) {
+ if (mrb->irep[i]) {
+ if (mrb->irep[i]->iseq)
+ mrb_free(mrb, mrb->irep[i]->iseq);
+
+ if (mrb->irep[i]->pool)
+ mrb_free(mrb, mrb->irep[i]->pool);
+
+ if (mrb->irep[i]->syms)
+ mrb_free(mrb, mrb->irep[i]->syms);
+
+ mrb_free(mrb, mrb->irep[i]);
+ }
+ }
+ return ret;
+ }
+ return sirep + hex_to_uint8(bin_header.sirep);
+}
+
+static uint16_t
+hex_to_bin8(unsigned char *dst, unsigned char *src)
+{
+ dst[0] = (hex2bin[src[0]] << 4) | (hex2bin[src[1]]);
+ return 1;
+}
+
+static uint16_t
+hex_to_bin16(unsigned char *dst, unsigned char *src)
+{
+ dst[0] = (hex2bin[src[0]] << 4) | (hex2bin[src[1]]);
+ dst[1] = (hex2bin[src[2]] << 4) | (hex2bin[src[3]]);
+ return 2;
+}
+
+static uint16_t
+hex_to_bin32(unsigned char *dst, unsigned char *src)
+{
+ dst[0] = (hex2bin[src[0]] << 4) | (hex2bin[src[1]]);
+ dst[1] = (hex2bin[src[2]] << 4) | (hex2bin[src[3]]);
+ dst[2] = (hex2bin[src[4]] << 4) | (hex2bin[src[5]]);
+ dst[3] = (hex2bin[src[6]] << 4) | (hex2bin[src[7]]);
+ return 4;
+}
+
+static uint8_t
+hex_to_uint8(unsigned char *hex)
+{
+ return (unsigned char)hex2bin[hex[0]] << 4 |
+ (unsigned char)hex2bin[hex[1]];
+}
+
+static uint16_t
+hex_to_uint16(unsigned char *hex)
+{
+ return (uint16_t)hex2bin[hex[0]] << 12 |
+ (uint16_t)hex2bin[hex[1]] << 8 |
+ (uint16_t)hex2bin[hex[2]] << 4 |
+ (uint16_t)hex2bin[hex[3]];
+}
+
+static uint32_t
+hex_to_uint32(unsigned char *hex)
+{
+ return (uint32_t)hex2bin[hex[0]] << 28 |
+ (uint32_t)hex2bin[hex[1]] << 24 |
+ (uint32_t)hex2bin[hex[2]] << 20 |
+ (uint32_t)hex2bin[hex[3]] << 16 |
+ (uint32_t)hex2bin[hex[4]] << 12 |
+ (uint32_t)hex2bin[hex[5]] << 8 |
+ (uint32_t)hex2bin[hex[6]] << 4 |
+ (uint32_t)hex2bin[hex[7]];
+}
+
+static char*
+hex_to_str(char *hex, char *str, uint16_t *str_len)
+{
+ char *src, *dst;
+ uint16_t hex_len = strlen(hex);
+
+ *str_len = 0;
+
+ for (src = hex, dst = str; hex_len > 0; (*str_len)++, hex_len--) {
+ if (*src == '\\' && hex_len > 1) {
+ src++; hex_len--;
+ switch(*src) {
+ case 'a': *dst++ = '\a'/* BEL */; break;
+ case 'b': *dst++ = '\b'/* BS */; break;
+ case 't': *dst++ = '\t'/* HT */; break;
+ case 'n': *dst++ = '\n'/* LF */; break;
+ case 'v': *dst++ = '\v'/* VT */; break;
+ case 'f': *dst++ = '\f'/* FF */; break;
+ case 'r': *dst++ = '\r'/* CR */; break;
+ case '\"': /* fall through */
+ case '\'': /* fall through */
+ case '\?': /* fall through */
+ case '\\': *dst++ = *src; break;
+ default:break;
+ }
+ src++;
+ } else {
+ *dst++ = *src++;
+ }
+ }
+
+ return str;
+}
+