static void iv_open(t_iconvdrv *iv, char *tocode, char *fromcode) { int len; iconv_t cd; ErlDrvBinary *bin; if ((cd = iconv_open(tocode, fromcode)) == (iconv_t) -1) { driver_send_error(iv, &am_einval); } else { len = sizeof(iconv_t); if (!(bin = driver_alloc_binary(len+1))) { iconv_close(cd); driver_send_error(iv, &am_enomem); } else { memcpy(bin->orig_bytes, &cd, len); if (!strcasecmp(tocode + strlen(tocode) -6, "IGNORE")) { /* GLIBC's iconv is annoying and will throw the failure code for * invalid sequences even though we specify //IGNORE so we have to * keep track if we initalized this conversion handle with //IGNORE * or not so we can disregard the error. */ bin->orig_bytes[len] = 1; } else { bin->orig_bytes[len] = 0; } driver_send_bin(iv, bin, len+1); driver_free_binary(bin); } } return; }
static void md4drv_from_erlang(ErlDrvData drv_data, char *buf, int len) { MD4_CTX context; unsigned char digest[16]; t_md4drv *md4 = (t_md4drv *) drv_data; ErlDrvBinary *bin = NULL; MD4Init(&context); MD4Update(&context, buf, len); MD4Final(digest, &context); if (!(bin = driver_alloc_binary(16))) { driver_send_error(md4, &am_enomem); } else { memcpy(bin->orig_bytes, digest, 16); driver_send_bin(md4, bin, 16); driver_free_binary(bin); } return; }
static void iv_conv(t_iconvdrv *iv, iconv_t cd, char *ip, int ileft) { int oleft=OUTBUF_SZ; char *op; int len; ErlDrvBinary *bin; op = &outbuf[0]; /* Reset cd to initial state */ iconv(cd, NULL, NULL, NULL, NULL); if (iconv(cd, &ip, &ileft, &op, &oleft) == (size_t) -1) { if (errno == EILSEQ) driver_send_error(iv, &am_eilseq); else if (errno == EINVAL) driver_send_error(iv, &am_einval); else if (errno == E2BIG) driver_send_error(iv, &am_e2big); else driver_send_error(iv, &am_unknown); } else if (ileft == 0) { len = OUTBUF_SZ - oleft; if (!(bin = driver_alloc_binary(len))) { driver_send_error(iv, &am_enomem); } else { memcpy(bin->orig_bytes, &outbuf[0], len); driver_send_bin(iv, bin, len); driver_free_binary(bin); } } return; }
static void iv_open(t_iconvdrv *iv, char *tocode, char *fromcode) { int len; iconv_t cd; ErlDrvBinary *bin; if ((cd = iconv_open(tocode, fromcode)) == (iconv_t) -1) { driver_send_error(iv, &am_einval); } else { len = sizeof(iconv_t); if (!(bin = driver_alloc_binary(len))) { iconv_close(cd); driver_send_error(iv, &am_enomem); } else { memcpy(bin->orig_bytes, &cd, len); driver_send_bin(iv, bin, len); driver_free_binary(bin); } } return; }
static void iv_conv(t_iconvdrv *iv, iconv_t cd, char *ip, size_t ileft, char ignore) { size_t oleft=ileft; char *op, *buf; int olen = ileft; ErlDrvBinary *bin; /* malloc enough for the input size, * with the assumption that the output length will be close to the input * length. This isn't always the case, but we realloc on E2BIG below. */ buf = malloc(olen); if (!buf) { driver_send_error(iv, &am_enomem); return; } op = buf; /* Reset cd to initial state */ iconv(cd, NULL, NULL, NULL, NULL); while (iconv(cd, &ip, &ileft, &op, &oleft) == (size_t) -1 && !(ignore && errno == EILSEQ)) { if (errno == EILSEQ) { driver_send_error(iv, &am_eilseq); } else if (errno == EINVAL) { driver_send_error(iv, &am_einval); } else if (errno == E2BIG) { char *newbuf; int newolen = olen + ileft + oleft; /* allocate as much additional space as iconv says we need */ newbuf = realloc(buf, newolen); if (!newbuf) { driver_send_error(iv, &am_enomem); goto free_and_return; } op = newbuf + (op - buf); buf = newbuf; olen = newolen; oleft = olen - (op - buf); /* keep going */ continue; } else { driver_send_error(iv, &am_unknown); } goto free_and_return; } if (ileft == 0) { /* find the length of the result */ olen = op - buf; if (!(bin = driver_alloc_binary(olen))) { driver_send_error(iv, &am_enomem); } else { memcpy(bin->orig_bytes, buf, olen); driver_send_bin(iv, bin, olen); driver_free_binary(bin); } } free_and_return: /* To ensure cleanup, this is the only exit point after an initial * successful malloc. */ free(buf); return; }