static int codec_drv_control( ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { codec_data* d = (codec_data*)handle; int ret = 0; ErlDrvBinary *out; *rbuf = NULL; int n = 0; // Number of frames int i = 0; // Temporary counter switch(command) { case CMD_ENCODE: if (len % 160 != 0) break; n = len / 160; // Calculate a number of frames out = driver_alloc_binary(n*10); // n*80 bits ret = n*10; for(i = 0; i<n; i++) bcg729Encoder(d->estate, (int16_t*)buf+80*i, (uint8_t*)out->orig_bytes+10*i); *rbuf = (char *) out; break; case CMD_DECODE: if (len % 10 != 0) break; n = len / 10; // Calculate a number of frames out = driver_alloc_binary(n*160); // n*160 bytes ret = n*160; for(i = 0; i<n; i++) bcg729Decoder(d->dstate, ((uint8_t*)buf)+10*i, 0, (int16_t*)out->orig_bytes+80*i); *rbuf = (char *) out; break; default: break; } return ret; }
void es_peepEvents2(ErlDrvPort port, ErlDrvTermData caller, char *bp) { SDL_Event events[256]; int numevents, res, i, sz; Uint32 mask; char *start; ErlDrvBinary * bin; ErlDrvTermData rt[8]; mask = * (Uint32 *) bp; bp += sizeof(Uint32); numevents = *bp++; SDL_PumpEvents(); res = SDL_PeepEvents(events, numevents, SDL_GETEVENT, mask); bin = driver_alloc_binary(res*MAX_EVENT_SIZE); bp = start = bin->orig_bytes; for (i = 0; i < res; i++) { bp = encode_event(&(events[i]), bp); } sz = bp-start; rt[0] = ERL_DRV_ATOM; rt[1]=driver_mk_atom((char *) "_esdl_result_"); rt[2] = ERL_DRV_BINARY; rt[3] = (ErlDrvTermData) bin; rt[4] = sz; rt[5] = 0; rt[6] = ERL_DRV_TUPLE; rt[7] = 2; driver_send_term(port,caller,rt,8); driver_free_binary(bin); }
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; }
ErlDrvSSizeT DriverController::control( ErlDrvData drv_data, const unsigned int command, char* buf, ErlDrvSizeT e_len, char** rbuf, ErlDrvSizeT e_rlen) { const size_t len = static_cast<int>(e_len); const size_t rlen = static_cast<int>(e_rlen); Driver& drv = * reinterpret_cast<Driver*>( drv_data ); ParamDecoder params(buf, len); ResultEncoder result(*gp_driverMemoryManager, *rbuf, rlen); drv.handleCommand(params, result, command); ErlDrvSSizeT result_len = result.finalSize(); /* It is too long for rbuf, create new binary. */ if (result.isExtended()) { ErlDrvBinary* bin = driver_alloc_binary(result_len); if (bin == NULL) throw MemoryAllocationDriverError(POS, result_len); result.finalize(bin->orig_bytes); *rbuf = (char*) bin; } return result_len; }
static int iconv_erl_control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen) { int i; int size; int index = 0; int avail; size_t inleft, outleft; ErlDrvBinary *b; char *from, *to, *string, *stmp, *rstring, *rtmp; iconv_t cd; ei_decode_version(buf, &index, &i); ei_decode_tuple_header(buf, &index, &i); ei_get_type(buf, &index, &i, &size); from = malloc(size + 1); ei_decode_string(buf, &index, from); ei_get_type(buf, &index, &i, &size); to = malloc(size + 1); ei_decode_string(buf, &index, to); ei_get_type(buf, &index, &i, &size); stmp = string = malloc(size + 1); ei_decode_string(buf, &index, string); cd = iconv_open(to, from); if(cd == (iconv_t) -1) { cd = iconv_open("ascii", "ascii"); if(cd == (iconv_t) -1) { cd = iconv_open("ascii", "ascii"); } } outleft = avail = 4*size; inleft = size; rtmp = rstring = malloc(avail); iconv(cd, &stmp, &inleft, &rtmp, &outleft); size = rtmp - rstring; //printf("size=%d, res=%s\r\n", size, rstring); *rbuf = (char*)(b = driver_alloc_binary(size)); memcpy(b->orig_bytes, rstring, size); free(from); free(to); free(string); free(rstring); iconv_close(cd); return size; }
int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller) { ErlDrvBinary* bin; int i; int num_vertices; GLdouble *n; int AP; int a_max = 2; int i_max = 6; num_vertices = * (int *) buff; buff += 8; /* Align */ n = (double *) buff; buff += 8*3; egl_tess.alloc_max = a_max*num_vertices*3; bin = driver_alloc_binary(egl_tess.alloc_max*sizeof(GLdouble)); egl_tess.error = 0; egl_tess.tess_coords = (double *) bin->orig_bytes; memcpy(egl_tess.tess_coords,buff,num_vertices*3*sizeof(GLdouble)); egl_tess.index_max = i_max*3*num_vertices; egl_tess.tess_index_list = (int *) driver_alloc(sizeof(int) * egl_tess.index_max); egl_tess.tess_coords = (double *) bin->orig_bytes; egl_tess.index_n = 0; egl_tess.alloc_n = num_vertices*3; gluTessNormal(tess, n[0], n[1], n[2]); gluTessBeginPolygon(tess, 0); gluTessBeginContour(tess); for (i = 0; i < num_vertices; i++) { gluTessVertex(tess, egl_tess.tess_coords+3*i, egl_tess.tess_coords+3*i); } gluTessEndContour(tess); gluTessEndPolygon(tess); AP = 0; ErlDrvTermData *rt; rt = (ErlDrvTermData *) driver_alloc(sizeof(ErlDrvTermData) * (13+egl_tess.index_n*2)); rt[AP++]=ERL_DRV_ATOM; rt[AP++]=driver_mk_atom((char *) "_egl_result_"); for(i=0; i < egl_tess.index_n; i++) { rt[AP++] = ERL_DRV_INT; rt[AP++] = (int) egl_tess.tess_index_list[i]; }; rt[AP++] = ERL_DRV_NIL; rt[AP++] = ERL_DRV_LIST; rt[AP++] = egl_tess.index_n+1; rt[AP++] = ERL_DRV_BINARY; rt[AP++] = (ErlDrvTermData) bin; rt[AP++] = egl_tess.alloc_n*sizeof(GLdouble); rt[AP++] = 0; rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Return tuple {list, Bin} rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Result tuple driver_send_term(port,caller,rt,AP); /* fprintf(stderr, "List %d: %d %d %d \r\n", */ /* res, */ /* n_pos, */ /* (tess_alloc_vertex-new_vertices)*sizeof(GLdouble), */ /* num_vertices*6*sizeof(GLdouble)); */ driver_free_binary(bin); driver_free(egl_tess.tess_index_list); driver_free(rt); return 0; }
static ErlDrvSSizeT sha_drv_control(ErlDrvData handle, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { ErlDrvBinary *b = NULL; switch (command) { #ifdef HAVE_MD2 case 2: rlen = MD2_DIGEST_LENGTH; b = driver_alloc_binary(rlen); if (b) MD2((unsigned char*)buf, len, (unsigned char*)b->orig_bytes); break; #endif case 224: rlen = SHA224_DIGEST_LENGTH; b = driver_alloc_binary(rlen); if (b) SHA224((unsigned char*)buf, len, (unsigned char*)b->orig_bytes); break; case 256: rlen = SHA256_DIGEST_LENGTH; b = driver_alloc_binary(rlen); if (b) SHA256((unsigned char*)buf, len, (unsigned char*)b->orig_bytes); break; case 384: rlen = SHA384_DIGEST_LENGTH; b = driver_alloc_binary(rlen); if (b) SHA384((unsigned char*)buf, len, (unsigned char*)b->orig_bytes); break; case 512: rlen = SHA512_DIGEST_LENGTH; b = driver_alloc_binary(rlen); if (b) SHA512((unsigned char*)buf, len, (unsigned char*)b->orig_bytes); break; }; if (b) { *rbuf = (char *)b; } else { *rbuf = NULL; rlen = 0; }; return rlen; }
/* Put elements from vec at q head */ int erts_ioq_pushqv(ErtsIOQueue *q, ErtsIOVec* vec, Uint skipbytes) { int n; Uint len; Uint size = vec->common.size - skipbytes; SysIOVec* iov; ErtsIOQBinary** binv; ErtsIOQBinary* b; if (q == NULL) return -1; ASSERT(vec->common.size >= skipbytes); if (vec->common.size <= skipbytes) return 0; n = skip(vec, skipbytes, &iov, &binv, &len); if (n < 0) return n; if (q->v_head - n < q->v_start) if (expandq(q, n, 0)) return -1; /* Queue and reference all binaries (remove zero length items) */ iov += (n-1); /* move to end */ binv += (n-1); /* move to end */ while(n--) { if ((len = iov->iov_len) > 0) { if ((b = *binv) == NULL) { /* special case create binary ! */ if (q->driver) { ErlDrvBinary *bin = driver_alloc_binary(len); if (!bin) return -1; sys_memcpy(bin->orig_bytes, iov->iov_base, len); b = (ErtsIOQBinary *)bin; q->v_head->iov_base = bin->orig_bytes; } *--q->b_head = b; q->v_head--; q->v_head->iov_len = len; } else { if (q->driver) driver_binary_inc_refc(&b->driver); else erts_refc_inc(&b->nif.intern.refc, 1); *--q->b_head = b; *--q->v_head = *iov; } } iov--; binv--; } q->size += size; /* update total size in queue */ return 0; }
/* ** Yet another malloc wrapper */ static ErlDrvBinary *my_alloc_binary(int size) { ErlDrvBinary *ret; if ((ret = driver_alloc_binary(size)) == NULL) { /* May or may not work... */ fprintf(stderr, "Could not allocate a binary of %lu bytes in %s.", (unsigned long) size, __FILE__); exit(1); } return ret; }
static int return_control_result(void* pLocalResult, int localLen, char **ppRetBuf, int returnLen) { if (*ppRetBuf == NULL || localLen > returnLen) { *ppRetBuf = (char*)driver_alloc_binary(localLen); if(*ppRetBuf == NULL) { return -1; } } memcpy(*ppRetBuf, pLocalResult, localLen); return localLen; }
static ErlDrvSSizeT control(ErlDrvData drvstate, unsigned int command, char *args, ErlDrvSizeT argslen, char **rbuf, ErlDrvSizeT rbuflen) { state *st = (state *)drvstate; init_state(st, args, argslen); switch (command) { case ENDWIN: do_endwin(st); break; case INITSCR: do_initscr(st); break; case REFRESH: do_refresh(st); break; case CBREAK: do_cbreak(st); break; case NOCBREAK: do_nocbreak(st); break; case ECHO: do_echo(st); break; case NOECHO: do_noecho(st); break; case ADDCH: do_addch(st); break; case ADDSTR: do_addstr(st); break; case MOVE: do_move(st); break; case GETYX: do_getyx(st); break; case GETMAXYX: do_getmaxyx(st); break; case CURS_SET: do_curs_set(st); break; case WERASE: do_werase(st); break; case HAS_COLORS: do_has_colors(st); break; case START_COLOR: do_start_color(st); break; case INIT_PAIR: do_init_pair(st); break; case WATTRON: do_wattron(st); break; case WATTROFF: do_wattroff(st); break; case NL: do_nl(st); break; case NONL: do_nonl(st); break; case SCROLLOK: do_scrollok(st); break; case MVADDCH: do_mvaddch(st); break; case MVADDSTR: do_mvaddstr(st); break; case NEWWIN: do_newwin(st); break; case DELWIN: do_delwin(st); break; case WMOVE: do_wmove(st); break; case WADDSTR: do_waddstr(st); break; case WADDCH: do_waddch(st); break; case MVWADDSTR: do_mvwaddstr(st); break; case MVWADDCH: do_mvwaddch(st); break; case WREFRESH: do_wrefresh(st); break; case WHLINE: do_whline(st); break; case WVLINE: do_wvline(st); break; case WBORDER: do_wborder(st); break; case BOX: do_box(st); break; case KEYPAD: do_keypad(st); break; default: break; } int rlen = st->eixb.index; ErlDrvBinary *response = driver_alloc_binary(rlen); memcpy(response->orig_bytes, st->eixb.buff, rlen); ei_x_free(&(st->eixb)); *rbuf = (char *)response; return rlen; }
static int zlib_output_init(ZLibData* d) { if (d->bin != NULL) driver_free_binary(d->bin); if ((d->bin = driver_alloc_binary(d->binsz_need)) == NULL) return -1; d->binsz = d->binsz_need; d->s.next_out = (unsigned char*)d->bin->orig_bytes; d->s.avail_out = d->binsz; return 0; }
void * edtk_driver_alloc_wrapper(size_t size) { ErlDrvBinary *eb; edtk_debug("%s: top", __FUNCTION__); if ((eb = driver_alloc_binary(size)) != NULL) { edtk_debug("%s: size %lu eb = 0x%lx orig_bytes = 0x%lx", __FUNCTION__, size, eb, eb->orig_bytes); return eb->orig_bytes; } else { return NULL; } }
static int codec_drv_control( ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { codec_data* d = (codec_data*)handle; int i; int ret = 0; ErlDrvBinary *out; *rbuf = NULL; float frame[FRAME_SIZE]; char cbits[200]; switch(command) { case CMD_ENCODE: for (i=0; i < len / 2; i++){ frame[i] = (buf[2*i] & 0xff) | (buf[2*i+1] << 8); } speex_bits_reset(&d->bits); speex_encode(d->estate, frame, &d->bits); ret = speex_bits_write(&d->bits, cbits, 200); out = driver_alloc_binary(ret); memcpy(out->orig_bytes, cbits, ret); *rbuf = (char *) out; break; case CMD_DECODE: out = driver_alloc_binary(2*FRAME_SIZE); speex_bits_read_from(&d->bits, buf, len); speex_decode_int(d->dstate, &d->bits, (spx_int16_t *)out->orig_bytes); ret = 2*FRAME_SIZE; *rbuf = (char *) out; break; default: break; } return ret; }
static ErlDrvSSizeT expat_erl_control(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { expat_data* d = (expat_data*)drv_data; int res, errcode; char *errstring; ErlDrvBinary *b; size_t size; switch (command) { case PARSE_COMMAND: case PARSE_FINAL_COMMAND: ei_x_new_with_version(&event_buf); ei_x_new(&xmlns_buf); res = XML_Parse(d->parser, buf, len, command == PARSE_FINAL_COMMAND); if(!res) { errcode = XML_GetErrorCode(d->parser); errstring = (char *)XML_ErrorString(errcode); ei_x_encode_list_header(&event_buf, 1); ei_x_encode_tuple_header(&event_buf, 2); ei_x_encode_long(&event_buf, XML_ERROR); ei_x_encode_tuple_header(&event_buf, 2); ei_x_encode_long(&event_buf, errcode); ei_x_encode_binary(&event_buf, errstring, strlen(errstring)); } ei_x_encode_empty_list(&event_buf); size = event_buf.index; b = driver_alloc_binary(size); memcpy(b->orig_bytes, event_buf.buff, size); ei_x_free(&event_buf); ei_x_free(&xmlns_buf); *rbuf = (char *)b; return size; default: return 0; } }
static void video_async_decode(void *async_data){ H264Frame *frame = (H264Frame *)async_data; H264Decoder *handle = frame->decoder; AVCodecContext *avctx = handle->dec; AVCodec *codec = avctx->codec; AVPacket avpkt; av_init_packet(&avpkt); struct timeval tv1; struct timeval tv2; gettimeofday(&tv1, NULL); int frame_ready = 0, len,i; AVFrame *decoded; decoded = avcodec_alloc_frame(); frame_ready = sizeof(AVFrame)*2; avpkt.data = (uint8_t *)frame->h264->orig_bytes; avpkt.size = frame->h264->orig_size; len = avcodec_decode_video2(handle->dec, decoded, &frame_ready, &avpkt); // av_log(avctx,AV_LOG_ERROR,"\nORIGSIZE: %i; LEN %i \n",avpkt.size,len); if(len == -1) { av_free(decoded); return; }; if(frame_ready) { int width = handle->dec->width; int height = handle->dec->height; if(handle->scale_ctx==NULL) { fprintf(stderr, "Started stream from camera %dx%d\r\n", width, height); handle->scale_ctx = sws_getContext( width, height, avctx->pix_fmt, width, height, avctx->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL ); } int stride_size = width*height; frame->yuv = driver_alloc_binary(stride_size*3/2); uint8_t *yuv_data = (uint8_t *)frame->yuv->orig_bytes; uint8_t *plane[4] = {yuv_data, yuv_data+stride_size, yuv_data+stride_size+stride_size/4, NULL}; int stride[4] = {width, width/2, width/2, 0}; sws_scale(handle->scale_ctx, (const uint8_t **)decoded->data, decoded->linesize, 0, height, plane, stride); } gettimeofday(&tv2, NULL); handle->total_time += (tv2.tv_sec * 1000 + tv2.tv_usec / 1000) - (tv1.tv_sec * 1000 + tv1.tv_usec / 1000); av_free(decoded); driver_free_binary(frame->h264); }
/* general control reply function */ static ErlDrvSSizeT ctl_reply(int rep, char* buf, ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rsize) { char* ptr; if ((len+1) > rsize) { ErlDrvBinary* bin = driver_alloc_binary(len+1); if (bin == NULL) return -1; ptr = bin->orig_bytes; *rbuf = (char*)ptr; } else ptr = *rbuf; *ptr++ = rep; memcpy(ptr, buf, len); return len+1; }
static ErtsIOQBinary *alloc_binary(Uint size, char *source, void **iov_base, int driver) { if (driver) { ErlDrvBinary *bin = driver_alloc_binary(size); if (!bin) return NULL; sys_memcpy(bin->orig_bytes, source, size); *iov_base = bin->orig_bytes; return (ErtsIOQBinary *)bin; } else { /* This clause can be triggered in enif_ioq_enq_binary is used */ Binary *bin = erts_bin_nrml_alloc(size); if (!bin) return NULL; erts_refc_init(&bin->intern.refc, 1); sys_memcpy(bin->orig_bytes, source, size); *iov_base = bin->orig_bytes; return (ErtsIOQBinary *)bin; } }
static void get_blob(Cmd *cmd) { char *buff = cmd->data; int len = cmd->size; Gd *gd = cmd->gd; int index = 0; void *imgData = NULL; int size = 0; ErlDrvBinary * bin; long quality; ei_decode_version(buff, &index, NULL); ei_decode_long(buff, &index, &quality); if (NULL == gd->image) { driver_failure_atom(gd->port, "null_image"); return; } imgData = gd->blob(gd->image, &size, quality); if (NULL == imgData) { driver_failure_posix(gd->port, ENOMEM); return; } bin = driver_alloc_binary(size); if (NULL == bin) { driver_failure_posix(gd->port, ENOMEM); return; } memcpy(bin->orig_bytes, imgData, size); gdFree(imgData); ErlDrvTermData spec[] = { ERL_DRV_PORT, driver_mk_port(gd->port), ERL_DRV_ATOM, driver_mk_atom("ok"), ERL_DRV_BINARY, bin, size, 0, ERL_DRV_TUPLE, 3}; driver_output_term(gd->port, spec, sizeof(spec) / sizeof(ERL_DRV_PORT)); driver_free_binary(bin); }
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; }
void es_waitEvent2(ErlDrvPort port, ErlDrvTermData caller) { SDL_Event event; ErlDrvBinary * bin; ErlDrvTermData rt[8]; char *bp, *start; int sz; bin = driver_alloc_binary(MAX_EVENT_SIZE); bp = start = bin->orig_bytes; SDL_WaitEvent(&event); bp = encode_event(&event, bp); sz = bp-start; rt[0] = ERL_DRV_ATOM; rt[1]=driver_mk_atom((char *) "_esdl_result_"); rt[2] = ERL_DRV_BINARY; rt[3] = (ErlDrvTermData) bin; rt[4] = sz; rt[5] = 0; rt[6] = ERL_DRV_TUPLE; rt[7] = 2; driver_send_term(port,caller,rt,8); driver_free_binary(bin); }
static void audio_async_decode(void *async_data){ H264Frame *frame = (H264Frame *)async_data; H264Decoder *handle = frame->decoder; int16_t *outbuf=NULL; int len; int size_out; outbuf=av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE*2); AVPacket avpkt; avpkt.data = (uint8_t *)frame->h264->orig_bytes; avpkt.size = frame->h264->orig_size; size_out = AVCODEC_MAX_AUDIO_FRAME_SIZE*2; len = avcodec_decode_audio3(handle->dec, outbuf, &size_out,&avpkt); if(len == -1) { av_free(outbuf); return; }; frame->sample = driver_alloc_binary(size_out); memcpy(frame->sample->orig_bytes,outbuf,size_out); frame->sample->orig_size = size_out; av_free(outbuf); driver_free_binary(frame->h264); }
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, 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 ErlDrvSSizeT iconv_erl_control(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { int i; int size; int index = 0; int avail; size_t inleft, outleft; ErlDrvBinary *b; char *from, *to, *string, *stmp, *rstring, *rtmp; iconv_t cd; int invalid_utf8_as_latin1 = 0; ei_decode_version(buf, &index, &i); ei_decode_tuple_header(buf, &index, &i); ei_get_type(buf, &index, &i, &size); from = driver_alloc(size + 1); ei_decode_string(buf, &index, from); ei_get_type(buf, &index, &i, &size); to = driver_alloc(size + 1); ei_decode_string(buf, &index, to); ei_get_type(buf, &index, &i, &size); stmp = string = driver_alloc(size + 1); ei_decode_string(buf, &index, string); /* Special mode: parse as UTF-8 if possible; otherwise assume it's Latin-1. Makes no difference when encoding. */ if (strcmp(from, "utf-8+latin-1") == 0) { from[5] = '\0'; invalid_utf8_as_latin1 = 1; } if (strcmp(to, "utf-8+latin-1") == 0) { to[5] = '\0'; } cd = iconv_open(to, from); if (cd == (iconv_t) -1) { cd = iconv_open("ascii", "ascii"); if (cd == (iconv_t) -1) { *rbuf = (char*)(b = driver_alloc_binary(size)); memcpy(b->orig_bytes, string, size); driver_free(from); driver_free(to); driver_free(string); return size; } } outleft = avail = 4*size; inleft = size; rtmp = rstring = driver_alloc(avail); while (inleft > 0) { if (iconv(cd, &stmp, &inleft, &rtmp, &outleft) == (size_t) -1) { if (invalid_utf8_as_latin1 && (*stmp & 0x80) && outleft >= 2) { /* Encode one byte of (assumed) Latin-1 into two bytes of UTF-8 */ *rtmp++ = 0xc0 | ((*stmp & 0xc0) >> 6); *rtmp++ = 0x80 | (*stmp & 0x3f); outleft -= 2; } stmp++; inleft--; } }
while (inleft > 0) { if (iconv(cd, &stmp, &inleft, &rtmp, &outleft) == (size_t) -1) { if (invalid_utf8_as_latin1 && (*stmp & 0x80) && outleft >= 2) { /* Encode one byte of (assumed) Latin-1 into two bytes of UTF-8 */ *rtmp++ = 0xc0 | ((*stmp & 0xc0) >> 6); *rtmp++ = 0x80 | (*stmp & 0x3f); outleft -= 2; } stmp++; inleft--; } } size = rtmp - rstring; *rbuf = (char*)(b = driver_alloc_binary(size)); memcpy(b->orig_bytes, rstring, size); driver_free(from); driver_free(to); driver_free(string); driver_free(rstring); iconv_close(cd); return size; } ErlDrvEntry iconv_driver_entry = { NULL, /* F_PTR init, N/A */
static int exmpp_xml_control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen) { struct exmpp_xml_data *edd; ei_x_buff *to_return; ErlDrvBinary *bin; int size, ret; edd = (struct exmpp_xml_data *)drv_data; size = 0; bin = NULL; to_return = NULL; switch (command) { /* * Parsing. */ case COMMAND_PARSE: case COMMAND_PARSE_FINAL: if (edd->parser == NULL) { /* Start a parser. */ if (create_parser(edd) != 0) { to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_ERROR; ei_x_encode_atom(to_return, "parser_setup_failed"); break; } } /* Control the total size of data to parse. */ if (!is_data_size_under_limit(&edd->ctx, len)) { to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_ERROR; ei_x_encode_atom(to_return, "stanza_too_big"); break; } /* Run XML document parsing. */ ret = XML_Parse(edd->parser, buf, len, command == COMMAND_PARSE_FINAL); if (!ret) { enum XML_Error errcode; const char *errmsg; /* An error occured during parsing; most probably, * XML wasn't well-formed. */ errcode = XML_GetErrorCode(edd->parser); errmsg = XML_ErrorString(errcode); to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_ERROR; ei_x_encode_tuple_header(to_return, 2); ei_x_encode_atom(to_return, "parsing_failed"); ei_x_encode_tuple_header(to_return, 2); ei_x_encode_long(to_return, errcode); ei_x_encode_string(to_return, errmsg); break; } /* Return the complete tree(s). */ ret = RET_OK; if (edd->ctx.complete_trees_ready) { /* Terminate the complete trees list. */ ei_x_encode_empty_list(edd->ctx.complete_trees); to_return = edd->ctx.complete_trees; size = 1 + to_return->index; bin = driver_alloc_binary(size); if (bin == NULL) return (-1); bin->orig_bytes[0] = (char)ret; memcpy(bin->orig_bytes + 1, to_return->buff, to_return->index); } else { /* We need more data to produce a tree. */ to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ei_x_encode_atom(to_return, command == COMMAND_PARSE ? "continue" : "done"); } if (command == COMMAND_PARSE) { /* Update the size of processed data. */ add_data_size(&edd->ctx, len); /* Reset the complete trees list. */ reset_complete_trees(&edd->ctx); } else { /* We're done with the parser. */ destroy_parser(edd); } break; case COMMAND_RESET_PARSER: if (edd->parser != NULL) { reset_context(&edd->ctx); XML_ParserReset(edd->parser, "UTF-8"); init_parser(edd); } ret = RET_OK; break; /* * Misc. */ case COMMAND_PORT_REVISION: /* Store the revision in the buffer. */ to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = RET_OK; ei_x_encode_string(to_return, "$Revision$"); break; default: /* Other commands are handled in 'exmpp_xml.c' */ to_return = exmpp_new_xbuf(); if (to_return == NULL) return (-1); ret = control(&edd->ctx, command, buf, to_return); if (ret < 0) return (-1); } if (bin == NULL) { if (to_return != NULL) { size = 1 + to_return->index; bin = driver_alloc_binary(size); if (bin == NULL) return (-1); bin->orig_bytes[0] = (char)ret; if (to_return->index > 0) memcpy(bin->orig_bytes + 1, to_return->buff, to_return->index); exmpp_free_xbuf(to_return); } else { /* The command called doesn't return anything. */ size = 1; bin = driver_alloc_binary(size); bin->orig_bytes[0] = RET_OK; } } /* Set the returned buffer. */ *rbuf = (char *)bin; /* Return the size of this buffer. */ return (size); }
static int tls_drv_control(ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { tls_data *d = (tls_data *)handle; int res; int size; ErlDrvBinary *b; X509 *cert; unsigned int flags = command; command &= 0xffff; ERR_clear_error(); switch (command) { case SET_CERTIFICATE_FILE_ACCEPT: case SET_CERTIFICATE_FILE_CONNECT: { time_t mtime = 0; SSL_CTX *ssl_ctx = hash_table_lookup(buf, &mtime); if (is_key_file_modified(buf, &mtime) || ssl_ctx == NULL) { SSL_CTX *ctx; hash_table_insert(buf, mtime, NULL); ctx = SSL_CTX_new(SSLv23_method()); die_unless(ctx, "SSL_CTX_new failed"); res = SSL_CTX_use_certificate_chain_file(ctx, buf); die_unless(res > 0, "SSL_CTX_use_certificate_file failed"); res = SSL_CTX_use_PrivateKey_file(ctx, buf, SSL_FILETYPE_PEM); die_unless(res > 0, "SSL_CTX_use_PrivateKey_file failed"); res = SSL_CTX_check_private_key(ctx); die_unless(res > 0, "SSL_CTX_check_private_key failed"); SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_default_verify_paths(ctx); #ifdef SSL_MODE_RELEASE_BUFFERS SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); #endif if (command == SET_CERTIFICATE_FILE_ACCEPT) { SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback); } ssl_ctx = ctx; hash_table_insert(buf, mtime, ssl_ctx); } d->ssl = SSL_new(ssl_ctx); die_unless(d->ssl, "SSL_new failed"); if (flags & VERIFY_NONE) SSL_set_verify(d->ssl, SSL_VERIFY_NONE, verify_callback); d->bio_read = BIO_new(BIO_s_mem()); d->bio_write = BIO_new(BIO_s_mem()); SSL_set_bio(d->ssl, d->bio_read, d->bio_write); if (command == SET_CERTIFICATE_FILE_ACCEPT) { SSL_set_options(d->ssl, SSL_OP_NO_TICKET); SSL_set_accept_state(d->ssl); } else { SSL_set_options(d->ssl, SSL_OP_NO_SSLv2|SSL_OP_NO_TICKET); SSL_set_connect_state(d->ssl); } break; } case SET_ENCRYPTED_INPUT: die_unless(d->ssl, "SSL not initialized"); BIO_write(d->bio_read, buf, len); break; case SET_DECRYPTED_OUTPUT: die_unless(d->ssl, "SSL not initialized"); res = SSL_write(d->ssl, buf, len); if (res <= 0) { res = SSL_get_error(d->ssl, res); if (res == SSL_ERROR_WANT_READ || res == SSL_ERROR_WANT_WRITE) { b = driver_alloc_binary(1); b->orig_bytes[0] = 2; *rbuf = (char *)b; return 1; } else { die_unless(0, "SSL_write failed"); } } break; case GET_ENCRYPTED_OUTPUT: die_unless(d->ssl, "SSL not initialized"); size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; while ((res = BIO_read(d->bio_write, b->orig_bytes + rlen, BUF_SIZE)) > 0) { //printf("%d bytes of encrypted data read from state machine\r\n", res); rlen += res; size += BUF_SIZE; b = driver_realloc_binary(b, size); } b = driver_realloc_binary(b, rlen); *rbuf = (char *)b; return rlen; case GET_DECRYPTED_INPUT: if (!SSL_is_init_finished(d->ssl)) { res = SSL_do_handshake(d->ssl); if (res <= 0) die_unless(SSL_get_error(d->ssl, res) == SSL_ERROR_WANT_READ, "SSL_do_handshake failed"); } else { size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; while ((res = SSL_read(d->ssl, b->orig_bytes + rlen, BUF_SIZE)) > 0) { //printf("%d bytes of decrypted data read from state machine\r\n",res); rlen += res; size += BUF_SIZE; b = driver_realloc_binary(b, size); } if (res < 0) { int err = SSL_get_error(d->ssl, res); if (err == SSL_ERROR_WANT_READ) { //printf("SSL_read wants more data\r\n"); //return 0; } // TODO } b = driver_realloc_binary(b, rlen); *rbuf = (char *)b; return rlen; } break; case GET_PEER_CERTIFICATE: cert = SSL_get_peer_certificate(d->ssl); if (cert == NULL) { b = driver_alloc_binary(1); b->orig_bytes[0] = 1; *rbuf = (char *)b; return 1; } else { unsigned char *tmp_buf; rlen = i2d_X509(cert, NULL); if (rlen >= 0) { rlen++; b = driver_alloc_binary(rlen); b->orig_bytes[0] = 0; tmp_buf = (unsigned char *)&b->orig_bytes[1]; i2d_X509(cert, &tmp_buf); X509_free(cert); *rbuf = (char *)b; return rlen; } else X509_free(cert); } break; case GET_VERIFY_RESULT: b = driver_alloc_binary(1); b->orig_bytes[0] = SSL_get_verify_result(d->ssl); *rbuf = (char *)b; return 1; break; } b = driver_alloc_binary(1); b->orig_bytes[0] = 0; *rbuf = (char *)b; return 1; }
static int ejabberd_zlib_drv_control(ErlDrvData handle, unsigned int command, char *buf, int len, char **rbuf, int rlen) { ejabberd_zlib_data *d = (ejabberd_zlib_data *)handle; int err; int size; ErlDrvBinary *b; switch (command) { case DEFLATE: size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; d->d_stream->next_in = (unsigned char *)buf; d->d_stream->avail_in = len; d->d_stream->avail_out = 0; err = Z_OK; while (err == Z_OK && d->d_stream->avail_out == 0) { d->d_stream->next_out = (unsigned char *)b->orig_bytes + rlen; d->d_stream->avail_out = BUF_SIZE; err = deflate(d->d_stream, Z_SYNC_FLUSH); die_unless((err == Z_OK) || (err == Z_STREAM_END), "Deflate error"); rlen += (BUF_SIZE - d->d_stream->avail_out); size += (BUF_SIZE - d->d_stream->avail_out); b = driver_realloc_binary(b, size); } b = driver_realloc_binary(b, rlen); *rbuf = (char *)b; return rlen; case INFLATE: size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; if (len > 0) { d->i_stream->next_in = (unsigned char *)buf; d->i_stream->avail_in = len; d->i_stream->avail_out = 0; err = Z_OK; while (err == Z_OK && d->i_stream->avail_out == 0) { d->i_stream->next_out = (unsigned char *)b->orig_bytes + rlen; d->i_stream->avail_out = BUF_SIZE; err = inflate(d->i_stream, Z_SYNC_FLUSH); die_unless((err == Z_OK) || (err == Z_STREAM_END), "Inflate error"); rlen += (BUF_SIZE - d->i_stream->avail_out); size += (BUF_SIZE - d->i_stream->avail_out); b = driver_realloc_binary(b, size); } } b = driver_realloc_binary(b, rlen); *rbuf = (char *)b; return rlen; } b = driver_alloc_binary(1); b->orig_bytes[0] = 0; *rbuf = (char *)b; return 1; }
static void uvc_drv_input(ErlDrvData handle, ErlDrvEvent io_event) { Uvc* d = (Uvc*) handle; struct v4l2_buffer buf; memset(&buf, 0, sizeof buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; int ret = ioctl(d->fd, VIDIOC_DQBUF, &buf); if(ret < 0) { driver_failure_posix(d->port, errno); return; } ErlDrvBinary* bin; size_t len; if(d->pixelformat == V4L2_PIX_FMT_YUYV) { len = d->width*d->height*3/2; bin = driver_alloc_binary(len); if(!d->scale_ctx) d->scale_ctx = sws_getContext( d->width, d->height, PIX_FMT_YUYV422, d->width, d->height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL ); int linesize[4] = {d->width*2, 0, 0, 0}; uint8_t *src[4] = {(uint8_t *)d->buffers[buf.index].mem, 0, 0, 0}; int stride_size = d->width*d->height; uint8_t *plane[4] = {(uint8_t *)bin->orig_bytes, (uint8_t *)bin->orig_bytes+stride_size, (uint8_t *)bin->orig_bytes+stride_size+stride_size/4, NULL}; int stride[4] = {d->width, d->width/2, d->width/2, 0}; sws_scale(d->scale_ctx, (const uint8_t * const*)src, linesize, 0, d->height, plane, stride); } else { bin = driver_alloc_binary(buf.bytesused + 1024); len = add_huffman((uint8_t *)bin->orig_bytes, (uint8_t *)d->buffers[buf.index].mem, buf.bytesused); } ErlDrvUInt64 pts = buf.timestamp.tv_sec * 1000 + buf.timestamp.tv_usec / 1000; ErlDrvTermData reply[] = { ERL_DRV_ATOM, driver_mk_atom("uvc"), ERL_DRV_PORT, driver_mk_port(d->port), ERL_DRV_ATOM, driver_mk_atom(d->pixelformat == V4L2_PIX_FMT_YUYV ? "yuv" : "jpeg"), ERL_DRV_UINT64, &pts, ERL_DRV_BINARY, (ErlDrvTermData)bin, (ErlDrvTermData)len, 0, ERL_DRV_TUPLE, 5 }; // fprintf(stderr, "Event in uvc: %lu %u %u\r\n", len, (unsigned)buf.timestamp.tv_sec, (unsigned)buf.timestamp.tv_usec); driver_output_term(d->port, reply, sizeof(reply) / sizeof(reply[0])); driver_free_binary(bin); ret = video_queue_buffer(d, buf.index); if(ret < 0) { driver_failure_posix(d->port, errno); return; } }