static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info, int* retvalp) { NifModPrivData* data = priv_data(env); ERL_NIF_TERM head, tail; unsigned ix; for (ix=0; ix<RT_MAX; ix++) { data->rt_arr[ix] = NULL; } for (head = load_info; enif_get_list_cell(env, head, &head, &tail); head = tail) { const ERL_NIF_TERM* arr; int arity; CHECK(enif_get_tuple(env, head, &arity, &arr)); switch (arity) { case 6: open_resource_type(env, arr); break; case 2: CHECK(arr[0] == am_return); CHECK(enif_get_int(env, arr[1], retvalp)); break; default: CHECK(0); } } CHECK(enif_is_empty_list(env, head)); }
static ERL_NIF_TERM pwrite_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifIOVec vec, *input = &vec; Sint64 bytes_written, offset; ERL_NIF_TERM tail; if(argc != 2 || !enif_is_number(env, argv[0]) || !enif_inspect_iovec(env, 64, argv[1], &tail, &input)) { return enif_make_badarg(env); } if(!enif_get_int64(env, argv[0], &offset) || offset < 0) { return posix_error_to_tuple(env, EINVAL); } bytes_written = efile_pwritev(d, offset, input->iov, input->iovcnt); if(bytes_written < 0) { return posix_error_to_tuple(env, d->posix_errno); } if(!enif_is_empty_list(env, tail)) { ASSERT(bytes_written > 0); return enif_make_tuple3(env, am_continue, enif_make_int64(env, bytes_written), tail); } return am_ok; }
ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ BIGNUM *other_pub_key = NULL, *dh_p = NULL, *dh_g = NULL; DH *dh_priv = DH_new(); /* Check the arguments and get my private key (dh_priv), the peer's public key (other_pub_key), the parameters p & q */ { BIGNUM *dummy_pub_key = NULL, *priv_key = NULL; ERL_NIF_TERM head, tail; if (!get_bn_from_bin(env, argv[0], &other_pub_key) || !get_bn_from_bin(env, argv[1], &priv_key) || !enif_get_list_cell(env, argv[2], &head, &tail) || !get_bn_from_bin(env, head, &dh_p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dh_g) || !enif_is_empty_list(env, tail) /* Note: DH_set0_key() does not allow setting only the * private key, although DH_compute_key() does not use the * public key. Work around this limitation by setting * the public key to a copy of the private key. */ || !(dummy_pub_key = BN_dup(priv_key)) || !DH_set0_key(dh_priv, dummy_pub_key, priv_key) || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g) ) { if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (other_pub_key) BN_free(other_pub_key); if (dummy_pub_key) BN_free(dummy_pub_key); if (priv_key) BN_free(priv_key); return enif_make_badarg(env); } } { ErlNifBinary ret_bin; int size; enif_alloc_binary(DH_size(dh_priv), &ret_bin); size = DH_compute_key(ret_bin.data, other_pub_key, dh_priv); BN_free(other_pub_key); DH_free(dh_priv); if (size<=0) { enif_release_binary(&ret_bin); return atom_error; } if (size != ret_bin.size) enif_realloc_binary(&ret_bin, size); return enif_make_binary(env, &ret_bin); } }
static inline int match_empty_list(ErlNifEnv* env, ERL_NIF_TERM term, State *st){ if(!enif_is_empty_list(env, term)){ return 0; } b_putc2('[', ']', st); return 1; }
static ERL_NIF_TERM create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { /* create(Nrows, Ncolumns, [[first row],[second row],...,[last row]]) -> Matrix */ unsigned nrows, ncols; unsigned i, j; ERL_NIF_TERM list, row, ret; Matrix* mx = NULL; if (!enif_get_uint(env, argv[0], &nrows) || nrows < 1 || !enif_get_uint(env, argv[1], &ncols) || ncols < 1) { goto badarg; } mx = alloc_matrix(env, nrows, ncols); list = argv[2]; for (i = 0; i<nrows; i++) { if (!enif_get_list_cell(env, list, &row, &list)) { goto badarg; } for (j = 0; j<ncols; j++) { ERL_NIF_TERM v; if (!enif_get_list_cell(env, row, &v, &row) || !get_number(env, v, &POS(mx,i,j))) { goto badarg; } } if (!enif_is_empty_list(env, row)) { goto badarg; } } if (!enif_is_empty_list(env, list)) { goto badarg; } ret = enif_make_resource(env, mx); enif_release_resource(mx); return ret; badarg: if (mx != NULL) { enif_release_resource(mx); } return enif_make_badarg(env); }
static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i) { ERL_NIF_TERM head, tail; const ERL_NIF_TERM *tmp_tuple; ErlNifBinary tmpbin; int arity; char *tuple1 = NULL, *tuple2 = NULL; if (enif_is_empty_list(env, term)) { cmds[i] = NULL; return 0; } if (!enif_get_list_cell(env, term, &head, &tail)) goto err; if (!enif_get_tuple(env, head, &arity, &tmp_tuple)) goto err; if (arity != 2) goto err; if (!enif_inspect_binary(env, tmp_tuple[0], &tmpbin)) goto err; if ((tuple1 = enif_alloc(tmpbin.size + 1)) == NULL) goto err; (void) memcpy(tuple1, tmpbin.data, tmpbin.size); tuple1[tmpbin.size] = '\0'; cmds[i] = tuple1; i++; if (!enif_inspect_binary(env, tmp_tuple[1], &tmpbin)) goto err; if (tmpbin.size == 0) { cmds[i] = NULL; } else { if ((tuple2 = enif_alloc(tmpbin.size + 1)) == NULL) goto err; (void) memcpy(tuple2, tmpbin.data, tmpbin.size); tuple2[tmpbin.size] = '\0'; cmds[i] = tuple2; } i++; return get_engine_load_cmd_list(env, tail, cmds, i); err: if (tuple1 != NULL) { i--; enif_free(tuple1); } cmds[i] = NULL; return -1; }
// convert an erlang term to a python object // return None if the type can't be converted static PyObject* pynerl_term_to_obj(ErlNifEnv* env, ERL_NIF_TERM term) { int vint; Py_ssize_t arity, i; long int vlong; double vdouble; char buff[BUFF_SIZE]; PyObject* obj; ERL_NIF_TERM list, head, tail; const ERL_NIF_TERM *terms; // TODO: add more types if (enif_get_long(env, term, &vlong)) { obj = PyLong_FromLong(vlong); } else if (enif_get_double(env, term, &vdouble)) { obj = PyFloat_FromDouble(vlong); } else if (enif_is_empty_list(env, term)) { obj = PyList_New(0); } else if (enif_get_tuple(env, term, &vint, &terms)) { arity = vint; obj = PyTuple_New(arity); for (i = 0; i < arity; i++) { PyTuple_SetItem(obj, i, pynerl_term_to_obj(env, terms[(int)i])); } } else if (enif_is_identical(term, enif_make_atom(env, "true"))) { obj = Py_True; } else if (enif_is_identical(term, enif_make_atom(env, "false"))) { obj = Py_False; } else if (enif_get_string(env, term, buff, BUFF_SIZE, ERL_NIF_LATIN1)) { obj = PyUnicode_FromString(buff); } else if (enif_get_list_cell(env, term, &head, &tail)) { obj = PyList_New(0); list = term; while (enif_get_list_cell(env, list, &head, &tail)) { PyList_Append(obj, pynerl_term_to_obj(env, head)); list = tail; } } else { obj = Py_None; } return obj; }
static ERL_NIF_TERM eval2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary script_binary; if (!enif_inspect_binary(env, argv[0], &script_binary)){ return enif_make_badarg(env); } if (!enif_is_list(env, argv[1])) { enif_release_binary(&script_binary); return enif_make_badarg(env); } mrb_state *mrb; mrbc_context *cxt; mrb = mrb_open(); if (mrb == NULL) { return enif_make_atom(env, "error"); } unsigned int mrb_argv_len; enif_get_list_length(env, argv[1], &mrb_argv_len); mrb_value mrb_argv = mrb_ary_new(mrb); ERL_NIF_TERM cur; for(cur = argv[1]; !enif_is_empty_list(env, cur); ) { ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); mrb_ary_push(mrb, mrb_argv, erl2mruby(env, mrb, head)); cur = tail; } mrb_define_global_const(mrb, "ARGV", mrb_argv); char *script = malloc(script_binary.size+1); strncpy(script, (const char *)script_binary.data, (int)script_binary.size); script[script_binary.size] = '\0'; cxt = mrbc_context_new(mrb); struct mrb_parser_state* st = mrb_parse_string(mrb, (const char *)script, cxt); int n = mrb_generate_code(mrb, st); mrb_pool_close(st->pool); mrb_value result = mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_nil_value()); ERL_NIF_TERM erl_result = mruby2erl(env, mrb, result); free(script); mrbc_context_free(mrb, cxt); mrb_close(mrb); enif_release_binary(&script_binary); return erl_result; }
jsval to_js_object(ErlNifEnv* env, JSContext* cx, ERL_NIF_TERM list) { JSObject* ret; jsval kval; jsval vval; jsid idp; ERL_NIF_TERM head; ERL_NIF_TERM tail; const ERL_NIF_TERM* pair; int arity; ret = JS_NewObject(cx, NULL, NULL, NULL); if(ret == NULL) return JSVAL_VOID; if(enif_is_empty_list(env, list)) { return OBJECT_TO_JSVAL(ret); } if(!enif_get_list_cell(env, list, &head, &tail)) { return JSVAL_VOID; } do { if(!enif_get_tuple(env, head, &arity, &pair)) { return JSVAL_VOID; } if(arity != 2) { return JSVAL_VOID; } kval = to_js_key(env, cx, pair[0]); if(kval == JSVAL_VOID) return JSVAL_VOID; if(!JS_ValueToId(cx, kval, &idp)) return JSVAL_VOID; vval = to_js(env, cx, pair[1]); if(vval == JSVAL_VOID) return JSVAL_VOID; if(!JS_SetPropertyById(cx, ret, idp, &vval)) { return JSVAL_VOID; } } while(enif_get_list_cell(env, tail, &head, &tail)); return OBJECT_TO_JSVAL(ret); }
int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) { /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */ ERL_NIF_TERM head, tail; BIGNUM *e, *n, *d; BIGNUM *p, *q; BIGNUM *dmp1, *dmq1, *iqmp; if (!enif_get_list_cell(env, key, &head, &tail) || !get_bn_from_bin(env, head, &e) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &n) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &d)) { return 0; } (void) RSA_set0_key(rsa, n, e, d); if (enif_is_empty_list(env, tail)) { return 1; } if (!enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &q) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dmp1) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dmq1) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &iqmp) || !enif_is_empty_list(env, tail)) { return 0; } (void) RSA_set0_factors(rsa, p, q); (void) RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp); return 1; }
// // Options = [ Option ] // Option = caseless | {offset, non_neg_integer()} // | {capture,ValueSpec} | {capture,ValueSpec,Type} // Type = index | binary // ValueSpec = all | all_but_first | first | none | ValueList // ValueList = [ ValueID ] // ValueID = int() | string() | atom() // static bool parse_match_options(ErlNifEnv* env, const ERL_NIF_TERM list, matchoptions& opts) { if (enif_is_empty_list(env, list)) return true; ERL_NIF_TERM L,H,T; for (L=list; enif_get_list_cell(env, L, &H, &T); L=T) { const ERL_NIF_TERM *tuple; int tuplearity = -1; if (enif_is_identical(H, a_caseless)) { // caseless opts.caseless = true; } else if (enif_get_tuple(env, H, &tuplearity, &tuple)) { if (tuplearity == 2 || tuplearity == 3) { // {offset,N} or {capture,ValueSpec} if (enif_is_identical(tuple[0], a_offset)) { // {offset, int()} int offset = 0; if (enif_get_int(env, tuple[1], &offset)) { opts.offset = offset; } else { return false; } } else if (enif_is_identical(tuple[0], a_capture)) { // {capture,ValueSpec,Type} parse_match_capture_options(env, opts, tuple, tuplearity); } } } else { return false; } } return true; }
int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) { /* key=[E,N] */ ERL_NIF_TERM head, tail; BIGNUM *e, *n; if (!enif_get_list_cell(env, key, &head, &tail) || !get_bn_from_bin(env, head, &e) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &n) || !enif_is_empty_list(env, tail)) { return 0; } (void) RSA_set0_key(rsa, n, e, NULL); return 1; }
// // Options = [ Option ] // Option = global // static bool parse_replace_options(ErlNifEnv* env, const ERL_NIF_TERM list, replaceoptions& opts) { if (enif_is_empty_list(env, list)) return true; ERL_NIF_TERM L,H,T; for (L=list; enif_get_list_cell(env, L, &H, &T); L=T) { if (enif_is_identical(H, a_global)) opts.global = true; else return false; } return true; }
/* * argv[0] an atom * argv[1] a binary * argv[2] a ref * argv[3] 'ok' * argv[4] a fun * argv[5] a pid * argv[6] a port * argv[7] an empty list * argv[8] a non-empty list * argv[9] a tuple */ static ERL_NIF_TERM check_is(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM ok_atom = enif_make_atom(env, "ok"); if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); if (!enif_is_binary(env, argv[1])) return enif_make_badarg(env); if (!enif_is_ref(env, argv[2])) return enif_make_badarg(env); if (!enif_is_identical(argv[3], ok_atom)) return enif_make_badarg(env); if (!enif_is_fun(env, argv[4])) return enif_make_badarg(env); if (!enif_is_pid(env, argv[5])) return enif_make_badarg(env); if (!enif_is_port(env, argv[6])) return enif_make_badarg(env); if (!enif_is_empty_list(env, argv[7])) return enif_make_badarg(env); if (!enif_is_list(env, argv[7])) return enif_make_badarg(env); if (!enif_is_list(env, argv[8])) return enif_make_badarg(env); if (!enif_is_tuple(env, argv[9])) return enif_make_badarg(env); return ok_atom; }
static void parse_match_capture_options(ErlNifEnv* env, matchoptions& opts, const ERL_NIF_TERM* tuple, int tuplearity) { bool vs_set = false; if (enif_is_atom(env, tuple[1])) { // ValueSpec = all | all_but_first | first | none if (enif_is_atom(env, tuple[1]) > 0) { if (enif_is_identical(tuple[1], a_all)) opts.vs = matchoptions::VS_ALL; else if (enif_is_identical(tuple[1], a_all_but_first)) opts.vs = matchoptions::VS_ALL_BUT_FIRST; else if (enif_is_identical(tuple[1], a_first)) opts.vs = matchoptions::VS_FIRST; else if (enif_is_identical(tuple[1], a_none)) opts.vs = matchoptions::VS_NONE; vs_set = true; } } else if (!enif_is_empty_list(env, tuple[1])) { // ValueSpec = ValueList // ValueList = [ ValueID ] // ValueID = int() | string() | atom() opts.vlist = tuple[1]; vs_set = true; opts.vs = matchoptions::VS_VLIST; } // Type = index | binary if (tuplearity == 3 && vs_set) { if (enif_is_identical(tuple[2], a_index)) opts.ct = matchoptions::CT_INDEX; else if (enif_is_identical(tuple[2], a_binary)) opts.ct = matchoptions::CT_BINARY; } }
static ERL_NIF_TERM mem_write_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { unsigned int i, l, data, err; int ar; char* ptr; ERL_NIF_TERM head, tail, list, *tpl; err = enif_get_list_length(env, argv[0], &l); if (!err) { goto error; } err = enif_get_tuple(env, argv[1], &ar, (const ERL_NIF_TERM**)(&tpl)); if (err) { err = nifty_get_ptr(env, tpl[0], (ptr_t*)&ptr); } if (!err) { goto error; } list = argv[0]; i = 0; while (!enif_is_empty_list(env, list)) { err = enif_get_list_cell(env, list, &head, &tail); list = tail; if (!err) { goto error; } err = enif_get_uint(env, head, &data); if (!err) { goto error; } *(ptr+i++) = (char)data; } return argv[1]; error: return enif_make_badarg(env); }
// // Options = [ Option ] // Option = caseless | {max_mem, int()} // static bool parse_compile_options(ErlNifEnv* env, const ERL_NIF_TERM list, re2::RE2::Options& opts) { if (enif_is_empty_list(env, list)) return true; ERL_NIF_TERM L,H,T; for (L=list; enif_get_list_cell(env, L, &H, &T); L=T) { const ERL_NIF_TERM *tuple; int tuplearity = -1; if (enif_is_identical(H, a_caseless)) { // caseless opts.set_case_sensitive(false); } else if (enif_get_tuple(env, H, &tuplearity, &tuple)) { if (tuplearity == 2) { if (enif_is_identical(tuple[0], a_max_mem)) { // {max_mem, int()} int max_mem = 0; if (enif_get_int(env, tuple[1], &max_mem)) opts.set_max_mem(max_mem); else return false; } } } else { return false; } } return true; }
static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el) { ErlNifBinary cdata, name; const ERL_NIF_TERM *tuple; int arity, ret = 0; if (enif_get_tuple(env, el, &arity, &tuple)) { if (arity == 2) { if (!ENIF_COMPARE(tuple[0], atom_xmlcdata)) { if (enif_inspect_iolist_as_binary(env, tuple[1], &cdata)) { crypt(env, rbuf, cdata.data, cdata.size); ret = 1; }; }; }; if (arity == 4) { if (!ENIF_COMPARE(tuple[0], atom_xmlelement)) { if (enif_inspect_iolist_as_binary(env, tuple[1], &name)) { buf_add_char(env, rbuf, '<'); buf_add_str(env, rbuf, (char *)name.data, name.size); ret = make_attrs(env, rbuf, tuple[2]); if (ret) { if (enif_is_empty_list(env, tuple[3])) { buf_add_str(env, rbuf, "/>", 2); } else { buf_add_char(env, rbuf, '>'); ret = make_elements(env, rbuf, tuple[3]); if (ret) { buf_add_str(env, rbuf, "</", 2); buf_add_str(env, rbuf, (char*)name.data, name.size); buf_add_char(env, rbuf, '>'); }; }; }; }; }; }; }; return ret; }
static ERL_NIF_TERM write_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifIOVec vec, *input = &vec; Sint64 bytes_written; ERL_NIF_TERM tail; if(argc != 1 || !enif_inspect_iovec(env, 64, argv[0], &tail, &input)) { return enif_make_badarg(env); } bytes_written = efile_writev(d, input->iov, input->iovcnt); if(bytes_written < 0) { return posix_error_to_tuple(env, d->posix_errno); } if(!enif_is_empty_list(env, tail)) { ASSERT(bytes_written > 0); return enif_make_tuple2(env, am_continue, tail); } return am_ok; }
static void push_nif_term(lua_State* lua, ERL_NIF_TERM message, ErlNifEnv* env, ErlNifResourceType* resource_type) { const int top = lua_gettop(lua); if(enif_is_atom(env, message)) { push_nif_atom(lua, message, env); } else if(enif_is_binary(env, message)) { // TODO @@@ binary also seems to be the custom types // that erlang makes. This may be OK, but maybe we should // think about putting a special type for them in lua push_nif_binary(lua, message, env); } else if(enif_is_list(env, message)) { if(enif_is_empty_list(env, message)) { luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_newtable(lua); } else { // TODO @@@ try to send it as an IO list first and // if that fails send it as a regular list push_nif_list(lua, message, env, resource_type); } } else if(enif_is_tuple(env, message)) { push_nif_tuple(lua, message, env, resource_type); } else if(enif_is_pid(env, message)) { push_nif_pid(lua, message, env); } else if(enif_is_ref(env, message)) { push_nif_ref(lua, message, env); } else if(enif_is_exception(env, message)) { //printf("#exception\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending an exception is not supported"); } else if(enif_is_fun(env, message)) { //printf("#fun\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending a function reference is not supported"); } else if(enif_is_port(env, message)) { //printf("#port\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending a port is not supported"); } else { // thank you r14 -- must be a number push_nif_number(lua, message, env); } assert(lua_gettop(lua) == top+1); }
ENTERM vm_call(JSContext* cx, JSObject* gl, job_ptr job) { ENTERM resp; ENTERM head; ENTERM tail; jsval func; jsval args[256]; jsval rval; jsid idp; int argc; // Get the function object. func = to_js(job->env, cx, job->name); if(func == JSVAL_VOID) { resp = vm_mk_error(job->env, util_mk_atom(job->env, "invalid_name")); goto send; } if(!JS_ValueToId(cx, func, &idp)) { resp = vm_mk_error(job->env, util_mk_atom(job->env, "internal_error")); goto send; } if(!JS_GetPropertyById(cx, gl, idp, &func)) { resp = vm_mk_error(job->env, util_mk_atom(job->env, "bad_property")); goto send; } if(JS_TypeOfValue(cx, func) != JSTYPE_FUNCTION) { resp = vm_mk_error(job->env, util_mk_atom(job->env, "not_a_function")); goto send; } // Creating function arguments. if(enif_is_empty_list(job->env, job->args)) { argc = 0; } else { if(!enif_get_list_cell(job->env, job->args, &head, &tail)) { resp = vm_mk_error(job->env, util_mk_atom(job->env, "invalid_argv")); goto send; } argc = 0; do { args[argc++] = to_js(job->env, cx, head); } while(enif_get_list_cell(job->env, tail, &head, &tail) && argc < 256); } // Call function if(!JS_CallFunctionValue(cx, gl, func, argc, args, &rval)) { if(job->error != 0) { resp = vm_mk_error(job->env, job->error); } else { resp = vm_mk_error(job->env, util_mk_atom(job->env, "unknown")); } } else { resp = vm_mk_ok(job->env, to_erl(job->env, cx, rval)); } send: return enif_make_tuple2(job->env, job->ref, resp); }
ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Encoder enc; Encoder* e = &enc; ErlNifBinary bin; ERL_NIF_TERM ret; ERL_NIF_TERM stack; ERL_NIF_TERM curr; ERL_NIF_TERM item; const ERL_NIF_TERM* tuple; int arity; ErlNifSInt64 lval; double dval; if(argc != 2) { return enif_make_badarg(env); } if(!enc_init(e, env, argv[1], &bin)) { return enif_make_badarg(env); } stack = enif_make_list(env, 1, argv[0]); while(!enif_is_empty_list(env, stack)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_identical(curr, e->atoms->ref_object)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_error(e, "invalid_object_pair"); goto done; } if(arity != 2) { ret = enc_error(e, "invalid_object_pair"); goto done; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_error(e, "invalid_object_key"); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_identical(curr, e->atoms->ref_array)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else if(enif_compare(curr, e->atoms->atom_null) == 0) { if(!enc_literal(e, "null", 4)) { ret = enc_error(e, "null"); goto done; } } else if(enif_compare(curr, e->atoms->atom_true) == 0) { if(!enc_literal(e, "true", 4)) { ret = enc_error(e, "true"); goto done; } } else if(enif_compare(curr, e->atoms->atom_false) == 0) { if(!enc_literal(e, "false", 5)) { ret = enc_error(e, "false"); goto done; } } else if(enif_is_binary(env, curr)) { if(!enc_string(e, curr)) { ret = enc_error(e, "invalid_string"); goto done; } } else if(enif_is_atom(env, curr)) { if(!enc_string(e, curr)) { ret = enc_error(e, "invalid_string"); goto done; } } else if(enif_get_int64(env, curr, &lval)) { if(!enc_long(e, lval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_double(env, curr, &dval)) { if(!enc_double(e, dval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_tuple(env, curr, &arity, &tuple)) { if(arity != 1) { ret = enc_error(e, "invalid_ejson"); goto done; } if(!enif_is_list(env, tuple[0])) { ret = enc_error(e, "invalid_object"); goto done; } if(!enc_start_object(e)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, tuple[0])) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, tuple[0], &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_error(e, "invalid_object_member"); goto done; } if(arity != 2) { ret = enc_error(e, "invalid_object_member_arity"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_error(e, "invalid_object_member_key"); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_list(env, curr)) { if(!enc_start_array(e)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else { if(!enc_unknown(e, curr)) { ret = enc_error(e, "internal_error"); goto done; } } } if(!enc_done(e, &item)) { ret = enc_error(e, "internal_error"); goto done; } if(e->iolen == 0) { ret = item; } else { ret = enif_make_tuple2(env, e->atoms->atom_partial, item); } done: enc_destroy(e); return ret; }
/* 0: list */ static ERL_NIF_TERM nif_alloc(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM head = {0}; ERL_NIF_TERM tail = {0}; int arity = 0; char key[MAXATOMLEN+1]; /* Includes terminating NULL */ const ERL_NIF_TERM *array = NULL; ERL_NIF_TERM resources = {0}; ErlNifBinary req = {0}; if (!enif_is_list(env, argv[0]) || enif_is_empty_list(env, argv[0])) return enif_make_badarg(env); resources = enif_make_list(env, 0); if (!enif_alloc_binary(0, &req)) return error_tuple(env, ENOMEM); tail = argv[0]; /* [binary(), {ptr, integer()}, {ptr, binary()}, ...] */ while (enif_get_list_cell(env, tail, &head, &tail)) { int index = req.size; ErlNifBinary bin = {0}; if (enif_inspect_binary(env, head, &bin)) { enif_realloc_binary(&req, req.size+bin.size); (void)memcpy(req.data+index, bin.data, bin.size); } else if (enif_get_tuple(env, head, &arity, &array)) { ALLOC_STATE *p = NULL; ERL_NIF_TERM res = {0}; size_t val = 0; ErlNifBinary initial = {0}; if ( (arity != 2) || !enif_get_atom(env, array[0], key, sizeof(key), ERL_NIF_LATIN1) || (strcmp(key, "ptr") != 0)) return enif_make_badarg(env); if ( !(enif_get_ulong(env, array[1], (unsigned long *)&val) && val > 0) && !(enif_inspect_binary(env, array[1], &initial) && initial.size > 0)) return enif_make_badarg(env); val = (initial.size > 0) ? initial.size : val; p = enif_alloc_resource(PROCKET_ALLOC_RESOURCE, sizeof(ALLOC_STATE)); if (p == NULL) return error_tuple(env, ENOMEM); p->size = val; p->buf = calloc(val, 1); if (p->buf == NULL) { enif_release_resource(p); return error_tuple(env, ENOMEM); } if (initial.size > 0) (void)memcpy(p->buf, initial.data, p->size); if (!enif_realloc_binary(&req, req.size+sizeof(void *))) return error_tuple(env, ENOMEM); (void)memcpy(req.data+index, &p->buf, sizeof(void *)); res = enif_make_resource(env, p); enif_release_resource(p); resources = enif_make_list_cell(env, res, resources); } else return enif_make_badarg(env); } return enif_make_tuple3(env, atom_ok, enif_make_binary(env, &req), resources); }
static mrb_value erl2mruby(ErlNifEnv* env, mrb_state* mrb, ERL_NIF_TERM term) { if (enif_is_atom(env, term)) { unsigned len; enif_get_atom_length(env, term, &len, ERL_NIF_LATIN1); char * atom_str = (char *)malloc(sizeof(char)*(len+1)); int r = enif_get_atom(env, term, atom_str, len+1, ERL_NIF_LATIN1); mrb_value value; if(strncmp(atom_str, "nil", r) == 0){ value = mrb_nil_value(); }else if(strncmp(atom_str, "true", r) == 0){ value = mrb_true_value(); }else if(strncmp(atom_str, "false", r) == 0){ value = mrb_false_value(); }else{ value = mrb_symbol_value(mrb_intern_cstr(mrb, atom_str)); } free(atom_str); return value; } else if (enif_is_binary(env, term)) { ErlNifBinary bin; enif_inspect_binary(env, term, &bin); return mrb_str_new(mrb, (const char *)bin.data, bin.size); } else if (enif_is_number(env, term)) { double d; if (enif_get_double(env, term, &d)) { return mrb_float_value(mrb, (mrb_float)d); } else { ErlNifSInt64 i; enif_get_int64(env, term, &i); return mrb_fixnum_value((mrb_int)i); } } else if (enif_is_empty_list(env, term)) { return mrb_ary_new(mrb); } else if (enif_is_list(env, term)) { unsigned len; enif_get_list_length(env, term, &len); mrb_value ary = mrb_ary_new(mrb); ERL_NIF_TERM cur; for (cur = term; !enif_is_empty_list(env, cur); ) { ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); mrb_ary_push(mrb, ary, erl2mruby(env, mrb, head)); cur = tail; } return ary; } else if (enif_is_tuple(env, term)) { int arity; const ERL_NIF_TERM * array; enif_get_tuple(env, term, &arity, &array); unsigned len = 0; enif_get_list_length(env, array[0], &len); mrb_value hash = mrb_hash_new(mrb); ERL_NIF_TERM cur; for(cur = array[0]; !enif_is_empty_list(env, cur); ){ ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); const ERL_NIF_TERM * array0; int arity0; enif_get_tuple(env, head, &arity0, &array0); mrb_hash_set(mrb, hash, erl2mruby(env, mrb, array0[0]), erl2mruby(env, mrb, array0[1])); cur = tail; } return hash; } else { return mrb_nil_value(); } }
ERL_NIF_TERM encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Encoder* e; jiffy_st* st = (jiffy_st*) enif_priv_data(env); ERL_NIF_TERM ret = 0; ERL_NIF_TERM stack; ERL_NIF_TERM curr; ERL_NIF_TERM item; const ERL_NIF_TERM* tuple; int arity; ErlNifSInt64 lval; double dval; size_t start; size_t processed; if(argc != 3) { return enif_make_badarg(env); } else if(!enif_get_resource(env, argv[0], st->res_enc, (void**) &e)) { return enif_make_badarg(env); } else if(!enif_is_list(env, argv[1])) { return enif_make_badarg(env); } else if(!enif_is_list(env, argv[2])) { return enif_make_badarg(env); } if(!enc_init(e, env)) { return enif_make_badarg(env); } stack = argv[1]; e->iolist = argv[2]; start = e->iosize + e->i; while(!enif_is_empty_list(env, stack)) { processed = (e->iosize + e->i) - start; if(should_yield(processed, e->bytes_per_iter)) { consume_timeslice(env, processed, e->bytes_per_iter); return enif_make_tuple4( env, st->atom_iter, argv[0], stack, e->iolist ); } if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_identical(curr, e->atoms->ref_object)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_obj_error(e, "invalid_object_member", item); goto done; } if(arity != 2) { ret = enc_obj_error(e, "invalid_object_member_arity", item); goto done; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_identical(curr, e->atoms->ref_array)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else if(enif_compare(curr, e->atoms->atom_null) == 0) { if(!enc_literal(e, "null", 4)) { ret = enc_error(e, "null"); goto done; } } else if(e->use_nil && enif_compare(curr, e->atoms->atom_nil) == 0) { if(!enc_literal(e, "null", 4)) { ret = enc_error(e, "null"); goto done; } } else if(enif_compare(curr, e->atoms->atom_true) == 0) { if(!enc_literal(e, "true", 4)) { ret = enc_error(e, "true"); goto done; } } else if(enif_compare(curr, e->atoms->atom_false) == 0) { if(!enc_literal(e, "false", 5)) { ret = enc_error(e, "false"); goto done; } } else if(enif_is_binary(env, curr)) { if(!enc_string(e, curr)) { ret = enc_obj_error(e, "invalid_string", curr); goto done; } } else if(enif_is_atom(env, curr)) { if(!enc_string(e, curr)) { ret = enc_obj_error(e, "invalid_string", curr); goto done; } } else if(enif_get_int64(env, curr, &lval)) { if(!enc_long(e, lval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_double(env, curr, &dval)) { if(!enc_double(e, dval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_tuple(env, curr, &arity, &tuple)) { ret = enc_obj_error(e, "invalid_ejson", curr); goto done; #if MAP_TYPE_PRESENT } else if(enif_is_map(env, curr)) { if(!enc_map_to_ejson(env, curr, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); #endif } else if(enif_is_list(env, curr)) { if(enif_is_empty_list(env, curr)) { if(!enc_start_array(e) || !enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { if(!enc_start_array(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else { if(!enc_start_object(e)) { ret = enc_error(e, "internal_error"); goto done; } if(arity == 0) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } else if(arity != 2) { ret = enc_obj_error(e, "invalid_object_member_arity", item); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } } else { if(!enc_unknown(e, curr)) { ret = enc_error(e, "internal_error"); goto done; } } } if(!enc_done(e, &item)) { ret = enc_error(e, "internal_error"); goto done; } if(e->iolen == 0) { ret = item; } else { ret = enif_make_tuple2(env, e->atoms->atom_partial, item); } done: processed = (e->iosize + e->i) - start; consume_timeslice(env, processed, e->bytes_per_iter); return ret; }
ERL_NIF_TERM decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Decoder* d; jiffy_st* st = (jiffy_st*) enif_priv_data(env); ErlNifBinary bin; ERL_NIF_TERM objs; ERL_NIF_TERM curr; ERL_NIF_TERM val = argv[2]; ERL_NIF_TERM trailer; ERL_NIF_TERM ret; size_t bytes_read = 0; if(argc != 5) { return enif_make_badarg(env); } else if(!enif_inspect_binary(env, argv[0], &bin)) { return enif_make_badarg(env); } else if(!enif_get_resource(env, argv[1], st->res_dec, (void**) &d)) { return enif_make_badarg(env); } else if(!enif_is_list(env, argv[3])) { return enif_make_badarg(env); } else if(!enif_is_list(env, argv[4])) { return enif_make_badarg(env); } dec_init(d, env, argv[0], &bin); objs = argv[3]; curr = argv[4]; while(d->i < bin.size) { if(should_yield(env, &bytes_read, d->bytes_per_red)) { return enif_make_tuple5( env, st->atom_iter, argv[1], val, objs, curr ); } bytes_read += 1; switch(dec_curr(d)) { case st_value: switch(d->p[d->i]) { case ' ': case '\n': case '\r': case '\t': d->i++; break; case 'n': if(d->i + 3 >= d->len) { ret = dec_error(d, "invalid_literal"); goto done; } if(memcmp(&(d->p[d->i]), "null", 4) != 0) { ret = dec_error(d, "invalid_literal"); goto done; } val = d->null_term; dec_pop(d, st_value); d->i += 4; break; case 't': if(d->i + 3 >= d->len) { ret = dec_error(d, "invalid_literal"); goto done; } if(memcmp(&(d->p[d->i]), "true", 4) != 0) { ret = dec_error(d, "invalid_literal"); goto done; } val = d->atoms->atom_true; dec_pop(d, st_value); d->i += 4; break; case 'f': if(d->i + 4 >= bin.size) { ret = dec_error(d, "invalid_literal"); goto done; } if(memcmp(&(d->p[d->i]), "false", 5) != 0) { ret = dec_error(d, "invalid_literal"); goto done; } val = d->atoms->atom_false; dec_pop(d, st_value); d->i += 5; break; case '\"': if(!dec_string(d, &val)) { ret = dec_error(d, "invalid_string"); goto done; } dec_pop(d, st_value); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if(!dec_number(d, &val)) { ret = dec_error(d, "invalid_number"); goto done; } dec_pop(d, st_value); break; case '{': dec_push(d, st_object); dec_push(d, st_key); objs = enif_make_list_cell(env, curr, objs); curr = enif_make_list(env, 0); d->i++; break; case '[': dec_push(d, st_array); dec_push(d, st_value); objs = enif_make_list_cell(env, curr, objs); curr = enif_make_list(env, 0); d->i++; break; case ']': if(!enif_is_empty_list(env, curr)) { ret = dec_error(d, "invalid_json"); goto done; } dec_pop(d, st_value); if(dec_curr(d) != st_array) { ret = dec_error(d, "invalid_json"); goto done; } dec_pop(d, st_array); dec_pop(d, st_value); val = curr; // curr is [] if(!enif_get_list_cell(env, objs, &curr, &objs)) { ret = dec_error(d, "internal_error"); goto done; } d->i++; break; default: ret = dec_error(d, "invalid_json"); goto done; } if(dec_top(d) == 0) { dec_push(d, st_done); } else if(dec_curr(d) != st_value && dec_curr(d) != st_key) { dec_push(d, st_comma); curr = enif_make_list_cell(env, val, curr); } break; case st_key: switch(d->p[d->i]) { case ' ': case '\n': case '\r': case '\t': d->i++; break; case '\"': if(!dec_string(d, &val)) { ret = dec_error(d, "invalid_string"); goto done; } dec_pop(d, st_key); dec_push(d, st_colon); curr = enif_make_list_cell(env, val, curr); break; case '}': if(!enif_is_empty_list(env, curr)) { ret = dec_error(d, "invalid_json"); goto done; } dec_pop(d, st_key); dec_pop(d, st_object); dec_pop(d, st_value); val = make_empty_object(env, d->return_maps); if(!enif_get_list_cell(env, objs, &curr, &objs)) { ret = dec_error(d, "internal_error"); goto done; } if(dec_top(d) == 0) { dec_push(d, st_done); } else { dec_push(d, st_comma); curr = enif_make_list_cell(env, val, curr); } d->i++; break; default: ret = dec_error(d, "invalid_json"); goto done; } break; case st_colon: switch(d->p[d->i]) { case ' ': case '\n': case '\r': case '\t': d->i++; break; case ':': dec_pop(d, st_colon); dec_push(d, st_value); d->i++; break; default: ret = dec_error(d, "invalid_json"); goto done; } break; case st_comma: switch(d->p[d->i]) { case ' ': case '\n': case '\r': case '\t': d->i++; break; case ',': dec_pop(d, st_comma); switch(dec_curr(d)) { case st_object: dec_push(d, st_key); break; case st_array: dec_push(d, st_value); break; default: ret = dec_error(d, "internal_error"); goto done; } d->i++; break; case '}': dec_pop(d, st_comma); if(dec_curr(d) != st_object) { ret = dec_error(d, "invalid_json"); goto done; } dec_pop(d, st_object); dec_pop(d, st_value); if(!make_object(env, curr, &val, d->return_maps, d->dedupe_keys)) { ret = dec_error(d, "internal_object_error"); goto done; } if(!enif_get_list_cell(env, objs, &curr, &objs)) { ret = dec_error(d, "internal_error"); goto done; } if(dec_top(d) > 0) { dec_push(d, st_comma); curr = enif_make_list_cell(env, val, curr); } else { dec_push(d, st_done); } d->i++; break; case ']': dec_pop(d, st_comma); if(dec_curr(d) != st_array) { ret = dec_error(d, "invalid_json"); goto done; } dec_pop(d, st_array); dec_pop(d, st_value); val = make_array(env, curr); if(!enif_get_list_cell(env, objs, &curr, &objs)) { ret = dec_error(d, "internal_error"); goto done; } if(dec_top(d) > 0) { dec_push(d, st_comma); curr = enif_make_list_cell(env, val, curr); } else { dec_push(d, st_done); } d->i++; break; default: ret = dec_error(d, "invalid_json"); goto done; } break; case st_done: switch(d->p[d->i]) { case ' ': case '\n': case '\r': case '\t': d->i++; break; default: goto decode_done; } break; default: ret = dec_error(d, "invalid_internal_state"); goto done; } } decode_done: if(d->i < bin.size && d->return_trailer) { trailer = enif_make_sub_binary(env, argv[0], d->i, bin.size - d->i); val = enif_make_tuple3(env, d->atoms->atom_has_trailer, val, trailer); } else if(d->i < bin.size) { ret = dec_error(d, "invalid_trailing_data"); goto done; } if(dec_curr(d) != st_done) { ret = dec_error(d, "truncated_json"); } else if(d->is_partial) { ret = enif_make_tuple2(env, d->atoms->atom_partial, val); } else { ret = val; } done: return ret; }
int enc_json(Encoder* enc, ERL_NIF_TERM term) { int ival; unsigned int uival; long lval; unsigned long ulval; double dval; ERL_NIF_TERM head; ERL_NIF_TERM tail; int arity; const ERL_NIF_TERM* tuple; if(enif_is_atom(enc->env, term)) { return enc_atom(enc, term); } if(enif_is_binary(enc->env, term)) { return enc_binary(enc, term); } if(enif_get_int(enc->env, term, &ival)) { if(yajl_gen_integer(enc->handle, ival) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_integer"); return ERROR; } return OK; } if(enif_get_uint(enc->env, term, &uival)) { if(yajl_gen_integer(enc->handle, uival) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_unsigned_integer"); return ERROR; } return OK; } if(enif_get_long(enc->env, term, &lval)) { if(yajl_gen_integer(enc->handle, lval) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_long"); return ERROR; } return OK; } if(enif_get_ulong(enc->env, term, &ulval)) { if(yajl_gen_integer(enc->handle, ulval) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_unsigned_long"); return ERROR; } return OK; } if(enif_get_double(enc->env, term, &dval)) { if(yajl_gen_double(enc->handle, dval) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_double"); return ERROR; } return OK; } if(enif_is_empty_list(enc->env, term)) { if(yajl_gen_array_open(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_open_empty_list"); return ERROR; } if(yajl_gen_array_close(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_close_empty_list"); return ERROR; } return OK; } if(enif_get_list_cell(enc->env, term, &head, &tail)) { return enc_array(enc, head, tail); } if(enif_get_tuple(enc->env, term, &arity, &tuple)) { if(arity == 1) { if(enif_is_empty_list(enc->env, tuple[0])) { if(yajl_gen_map_open(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_open_empty_map"); return ERROR; } if(yajl_gen_map_close(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_close_empty_map"); return ERROR; } return OK; } else if(enif_get_list_cell(enc->env, tuple[0], &head, &tail)) { return enc_map(enc, head, tail); } } } enc->error = enif_make_tuple(enc->env, 2, enif_make_atom(enc->env, "badarg"), term ); return ERROR; }
jsval to_js(ErlNifEnv* env, JSContext* cx, ERL_NIF_TERM term) { int intval; unsigned int uintval; long longval; unsigned long ulongval; double doubleval; ERL_NIF_TERM head; ERL_NIF_TERM tail; const ERL_NIF_TERM* tuple; int arity; if(enif_is_atom(env, term)) { return to_js_special(env, cx, term); } if(enif_is_binary(env, term)) { return to_js_string(env, cx, term); } if(enif_is_empty_list(env, term)) { return to_js_empty_array(cx); } if(enif_get_int(env, term, &intval)) { return to_js_number(cx, (double) intval); } if(enif_get_uint(env, term, &uintval)) { return to_js_number(cx, (double) uintval); } if(enif_get_long(env, term, &longval)) { return to_js_number(cx, (double) longval); } if(enif_get_ulong(env, term, &ulongval)) { return to_js_number(cx, (double) ulongval); } if(enif_get_double(env, term, &doubleval)) { return to_js_number(cx, doubleval); } // enif doesn't seem to have any API to decode bignums, so use lower-level functions: if(is_big(term) && big_to_double(term, &doubleval) == 0) { return to_js_number(cx, doubleval); } if(enif_get_list_cell(env, term, &head, &tail)) { return to_js_array(env, cx, head, tail); } if(enif_get_tuple(env, term, &arity, &tuple)) { if(arity == 1) { return to_js_object(env, cx, tuple[0]); } } return JSVAL_VOID; }
ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ DH *dh_params = NULL; int mpint; /* 0 or 4 */ { ERL_NIF_TERM head, tail; BIGNUM *dh_p = NULL, *dh_g = NULL, *priv_key_in = NULL; unsigned long len = 0; if (!(get_bn_from_bin(env, argv[0], &priv_key_in) || argv[0] == atom_undefined) || !enif_get_list_cell(env, argv[1], &head, &tail) || !get_bn_from_bin(env, head, &dh_p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dh_g) || !enif_is_empty_list(env, tail) || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4) || !enif_get_ulong(env, argv[3], &len) /* Load dh_params with values to use by the generator. Mem mgmnt transfered from dh_p etc to dh_params */ || !(dh_params = DH_new()) || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in)) || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g) ) { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } if (len) { if (len < BN_num_bits(dh_p)) DH_set_length(dh_params, len); else { if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } } } #ifdef HAS_EVP_PKEY_CTX { EVP_PKEY_CTX *ctx; EVP_PKEY *dhkey, *params; int success; params = EVP_PKEY_new(); success = EVP_PKEY_set1_DH(params, dh_params); /* set the key referenced by params to dh_params... */ DH_free(dh_params); /* ...dh_params (and params) must be freed */ if (!success) return atom_error; ctx = EVP_PKEY_CTX_new(params, NULL); EVP_PKEY_free(params); if (!ctx) { return atom_error; } if (!EVP_PKEY_keygen_init(ctx)) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } dhkey = EVP_PKEY_new(); if (!EVP_PKEY_keygen(ctx, &dhkey)) { /* "performs a key generation operation, the ... */ /*... generated key is written to ppkey." (=last arg) */ /* EVP_PKEY_CTX_free(ctx); */ /* EVP_PKEY_free(dhkey); */ return atom_error; } dh_params = EVP_PKEY_get1_DH(dhkey); /* return the referenced key. dh_params and dhkey must be freed */ EVP_PKEY_free(dhkey); if (!dh_params) { /* EVP_PKEY_CTX_free(ctx); */ return atom_error; } EVP_PKEY_CTX_free(ctx); } #else if (!DH_generate_key(dh_params)) return atom_error; #endif { unsigned char *pub_ptr, *prv_ptr; int pub_len, prv_len; ERL_NIF_TERM ret_pub, ret_prv; const BIGNUM *pub_key_gen, *priv_key_gen; DH_get0_key(dh_params, &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen. "The values point to the internal representation of the public key and private key values. This memory should not be freed directly." says man */ pub_len = BN_num_bytes(pub_key_gen); prv_len = BN_num_bytes(priv_key_gen); pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); if (mpint) { put_int32(pub_ptr, pub_len); pub_ptr += 4; put_int32(prv_ptr, prv_len); prv_ptr += 4; } BN_bn2bin(pub_key_gen, pub_ptr); BN_bn2bin(priv_key_gen, prv_ptr); ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); DH_free(dh_params); return enif_make_tuple2(env, ret_pub, ret_prv); } }