static int make_attrs(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM attrs) { ErlNifBinary name, data; ERL_NIF_TERM head, tail; const ERL_NIF_TERM *tuple; int arity, ret = 1; while (enif_get_list_cell(env, attrs, &head, &tail)) { if (enif_get_tuple(env, head, &arity, &tuple)) { if (arity == 2) { if (enif_inspect_iolist_as_binary(env, tuple[0], &name) && enif_inspect_iolist_as_binary(env, tuple[1], &data)) { buf_add_char(env, rbuf, ' '); buf_add_str(env, rbuf, (char *)name.data, name.size); buf_add_str(env, rbuf, "='", 2); crypt(env, rbuf, data.data, data.size); buf_add_char(env, rbuf, '\''); attrs = tail; } else { ret = 0; break; }; } else { ret = 0; break; }; } else { ret = 0; break; }; }; return ret; }
static ERL_NIF_TERM unescape_attr(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary input; ERL_NIF_TERM output; struct buf *rbuf; int i; if (argc != 1) { return enif_make_badarg(env); } if (!enif_inspect_binary(env, argv[0], &input)) { return enif_make_badarg(env); } rbuf = init_buf(env, EXML_ATTR_BUF_SIZE); for (i = 0; i < input.size; i++) { if (input.data[i] == '&') { if (match_tag(input, i+1, "amp;", 4)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '&'); i += 4; } else if (match_tag(input, i+1, "apos;", 5)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '\''); i += 5; } else if (match_tag(input, i+1, "lt;", 3)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '<'); i += 3; } else if (match_tag(input, i+1, "gt;", 3)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '>'); i += 3; } else if (match_tag(input, i+1, "quot;", 5)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '"'); i += 5; } else if (match_tag(input, i+1, "#x9;", 4)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '\t'); i += 4; } else if (match_tag(input, i+1, "#xA;", 4)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '\n'); i += 4; } else if (match_tag(input, i+1, "#xD;", 4)) { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, '\r'); i += 4; } else { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, input.data[i]); } } else { buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, input.data[i]); } } unsigned char* data = enif_make_new_binary(env, rbuf->len, &output); memcpy((char*)data, rbuf->b, rbuf->len); destroy_buf(env, rbuf); return output; }
static ERL_NIF_TERM unescape_cdata(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary input; ERL_NIF_TERM output; struct buf *rbuf; int i; if (argc != 1) { return enif_make_badarg(env); } // CData should be iolist() or binary() if (enif_is_binary(env, argv[0])) { if (!enif_inspect_binary(env, argv[0], &input)) { return enif_make_badarg(env); } } else { if (!enif_inspect_iolist_as_binary(env, argv[0], &input)) { return enif_make_badarg(env); } } rbuf = init_buf(env, EXML_CDATA_BUF_SIZE); for (i = 0; i < input.size; i++) { if (input.data[i] == '&') { if (match_tag(input, i+1, "amp;", 4)) { buf_add_char(env, EXML_CDATA_BUF_SIZE, rbuf, '&'); i += 4; } else if (match_tag(input, i+1, "lt;", 3)) { buf_add_char(env, EXML_CDATA_BUF_SIZE, rbuf, '<'); i += 3; } else if (match_tag(input, i+1, "gt;", 3)) { buf_add_char(env, EXML_CDATA_BUF_SIZE, rbuf, '>'); i += 3; } else { buf_add_char(env, EXML_CDATA_BUF_SIZE, rbuf, input.data[i]); } } else { buf_add_char(env, EXML_CDATA_BUF_SIZE, rbuf, input.data[i]); } } unsigned char *data = enif_make_new_binary(env, rbuf->len, &output); memcpy(data, rbuf->b, rbuf->len); destroy_buf(env, rbuf); return output; }
inline void crypt(ErlNifEnv* env, struct buf *rbuf, unsigned char *data, int len) { int i; for (i = 0; i < len; i++) { switch (data[i]) { case '&': buf_add_str(env, rbuf, "&", 5); break; case '<': buf_add_str(env, rbuf, "<", 4); break; case '>': buf_add_str(env, rbuf, ">", 4); break; case '"': buf_add_str(env, rbuf, """, 6); break; case '\'': buf_add_str(env, rbuf, "'", 6); break; default: buf_add_char(env, rbuf, data[i]); break; }; }; }
static ERL_NIF_TERM escape_attr(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary input; ERL_NIF_TERM output; struct buf *rbuf; int i; if (argc != 1) { return enif_make_badarg(env); } if (!enif_inspect_binary(env, argv[0], &input)) { return enif_make_badarg(env); } rbuf = init_buf(env, EXML_ATTR_BUF_SIZE); for (i = 0; i < input.size; i++) { switch (input.data[i]) { case '&': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, "&", 5); break; case '<': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, "<", 4); break; case '>': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, ">", 4); break; case '"': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, """, 6); break; case '\'': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, "'", 6); break; case '\t': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, "	", 5); break; case '\n': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, "
", 5); break; case '\r': buf_add_str(env, EXML_ATTR_BUF_SIZE, rbuf, "
", 5); break; default: buf_add_char(env, EXML_ATTR_BUF_SIZE, rbuf, input.data[i]); break; }; }; unsigned char *data = enif_make_new_binary(env, rbuf->len, &output); memcpy(data, rbuf->b, rbuf->len); destroy_buf(env, rbuf); return output; }
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 escape_cdata(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary input; ERL_NIF_TERM output; struct buf *rbuf; int i; if (argc != 1) { return enif_make_badarg(env); } // CData should be iolist() or binary() if (enif_is_binary(env, argv[0])) { if (!enif_inspect_binary(env, argv[0], &input)) { return enif_make_badarg(env); } } else { if (!enif_inspect_iolist_as_binary(env, argv[0], &input)) { return enif_make_badarg(env); } } rbuf = init_buf(env, EXML_CDATA_BUF_SIZE); for (i = 0; i < input.size; i++) { switch (input.data[i]) { case '&': buf_add_str(env, EXML_CDATA_BUF_SIZE, rbuf, "&", 5); break; case '<': buf_add_str(env, EXML_CDATA_BUF_SIZE, rbuf, "<", 4); break; case '>': buf_add_str(env, EXML_CDATA_BUF_SIZE, rbuf, ">", 4); break; default: buf_add_char(env, EXML_CDATA_BUF_SIZE, rbuf, input.data[i]); break; }; }; unsigned char* data = enif_make_new_binary(env, rbuf->len, &output); memcpy(data, rbuf->b, rbuf->len); destroy_buf(env, rbuf); return output; }